@codedrifters/configulator 0.0.216 → 0.0.218
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 +25 -3
- package/lib/index.d.ts +25 -3
- package/lib/index.js +2841 -65
- package/lib/index.js.map +1 -1
- package/lib/index.mjs +2840 -65
- package/lib/index.mjs.map +1 -1
- package/package.json +1 -1
package/lib/index.mjs.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"sources":["../../utils/src/aws/aws-types.ts","../../utils/src/git/git-utils.ts","../../utils/src/string/string-utils.ts","../../utils/src/index.ts","../src/agent/agent-config.ts","../src/agent/types.ts","../src/agent/bundles/utils.ts","../src/agent/bundles/aws-cdk.ts","../src/agent/bundles/base.ts","../src/agent/bundles/project-context.ts","../src/agent/bundles/bcm-writer.ts","../src/agent/bundles/company-profile.ts","../src/agent/bundles/github-workflow.ts","../src/agent/bundles/industry-discovery.ts","../src/agent/bundles/jest.ts","../src/agent/bundles/maintenance-audit.ts","../src/agent/bundles/meeting-analysis.ts","../src/agent/bundles/orchestrator.ts","../src/agent/bundles/people-profile.ts","../src/pnpm/pnpm-workspace.ts","../src/agent/bundles/pnpm.ts","../src/agent/bundles/pr-review.ts","../src/agent/bundles/projen.ts","../src/agent/bundles/requirements-analyst.ts","../src/agent/bundles/research-pipeline.ts","../src/projects/project-metadata.ts","../src/agent/bundles/slack.ts","../src/agent/bundles/software-profile.ts","../src/turbo/turbo-repo.ts","../src/turbo/turbo-repo-task.ts","../src/agent/bundles/turborepo.ts","../src/agent/bundles/typescript.ts","../src/vitest/vitest-component.ts","../src/versions.ts","../src/agent/bundles/vitest.ts","../src/agent/bundles/index.ts","../src/agent/bundles/scope.ts","../src/agent/renderers/claude-renderer.ts","../src/agent/renderers/codex-renderer.ts","../src/agent/renderers/copilot-renderer.ts","../src/agent/renderers/cursor-renderer.ts","../src/agent/template-resolver.ts","../src/astro/astro-config.ts","../src/astro/astro-config-options.ts","../src/aws/aws-deployment-config.ts","../src/aws/aws-deployment-target.ts","../src/latest-eligible-version.ts","../src/version-package-map.ts","../src/jsii/jsii-faker.ts","../src/projects/astro-project.ts","../src/projects/typescript-project.ts","../src/projects/monorepo-project.ts","../src/tasks/reset-task.ts","../src/vscode/vscode.ts","../src/workflows/approve-merge-upgrade.ts","../src/workflows/build-complete-job.ts","../src/workflows/sync-labels.ts","../src/projects/aws-cdk-project.ts","../src/workflows/aws-deploy-workflow.ts","../src/workflows/aws-teardown-workflow.ts","../src/projects/starlight-project.ts","../src/typescript/typescript-config.ts"],"sourcesContent":["/**\n * Stage Types\n *\n * What stage of deployment is this? Dev, staging, or prod?\n */\nexport const AWS_STAGE_TYPE = {\n /**\n * Development environment, typically used for testing and development.\n */\n DEV: \"dev\",\n\n /**\n * Staging environment, used for pre-production testing.\n */\n STAGE: \"stage\",\n\n /**\n * Production environment, used for live deployments.\n */\n PROD: \"prod\",\n} as const;\n\n/**\n * Above const as a type.\n */\nexport type AwsStageType = (typeof AWS_STAGE_TYPE)[keyof typeof AWS_STAGE_TYPE];\n\n/**\n * Deployment target role: whether an (account, region) is the primary or\n * secondary deployment target (e.g. primary vs replica region).\n */\nexport const DEPLOYMENT_TARGET_ROLE = {\n /**\n * Account and region that represents the primary region for this service.\n * For example, the base DynamoDB Region for global tables.\n */\n PRIMARY: \"primary\",\n /**\n * Account and region that represents a secondary region for this service.\n * For example, a replica region for a global DynamoDB table.\n */\n SECONDARY: \"secondary\",\n} as const;\n\n/**\n * Type for deployment target role values.\n */\nexport type DeploymentTargetRoleType =\n (typeof DEPLOYMENT_TARGET_ROLE)[keyof typeof DEPLOYMENT_TARGET_ROLE];\n\n/**\n * Environment types (primary/secondary).\n *\n * @deprecated Use {@link DEPLOYMENT_TARGET_ROLE} instead. This constant is maintained for backward compatibility.\n */\nexport const AWS_ENVIRONMENT_TYPE = DEPLOYMENT_TARGET_ROLE;\n\n/**\n * Type for environment type values.\n *\n * @deprecated Use {@link DeploymentTargetRoleType} instead. This type is maintained for backward compatibility.\n */\nexport type AwsEnvironmentType = DeploymentTargetRoleType;\n","import { execSync } from \"node:child_process\";\n\n/**\n * Returns the current full git branch name\n *\n * ie: feature/1234 returns feature/1234\n *\n */\nexport const findGitBranch = (): string => {\n return execSync(\"git rev-parse --abbrev-ref HEAD\")\n .toString(\"utf8\")\n .replace(/[\\n\\r\\s]+$/, \"\");\n};\n\nexport const findGitRepoName = (): string => {\n /**\n * When running in github actions this will be populated.\n */\n if (process.env.GITHUB_REPOSITORY) {\n return process.env.GITHUB_REPOSITORY;\n }\n\n /**\n * locally, we need to extract the repo name from the git config.\n */\n const remote = execSync(\"git config --get remote.origin.url\")\n .toString(\"utf8\")\n .replace(/[\\n\\r\\s]+$/, \"\")\n .trim();\n\n const match = remote.match(/[:\\/]([^/]+\\/[^/]+?)(?:\\.git)?$/);\n const repoName = match ? match[1] : \"error-repo-name\";\n\n return repoName;\n};\n","import * as crypto from \"node:crypto\";\n\n/**\n *\n * @param inString string to hash\n * @param trimLength trim to this length (defaults to 999 chars)\n * @returns\n */\nexport const hashString = (inString: string, trimLength: number = 999) => {\n return crypto\n .createHash(\"sha256\")\n .update(inString)\n .digest(\"hex\")\n .substring(0, trimLength);\n};\n\n/**\n *\n * @param inputString string to truncate\n * @param maxLength max length of this string\n * @returns trimmed string\n */\nexport const trimStringLength = (inputString: string, maxLength: number) => {\n return inputString.length < maxLength\n ? inputString\n : inputString.substring(0, maxLength);\n};\n","export * from \"./aws/aws-types\";\nexport * from \"./git/git-utils\";\nexport * from \"./string/string-utils\";\n","import { Component, Project } from \"projen\";\nimport {\n AgentConfigOptions,\n AgentRuleBundle,\n ClaudeSettingsConfig,\n} from \"./agent-config-options\";\nimport { BUILT_IN_BUNDLES } from \"./bundles\";\nimport { scopeFilePatternsToProjects } from \"./bundles/scope\";\nimport { ProjectMetadata } from \"../projects/project-metadata\";\nimport { ResolvedProjectMetadata } from \"../projects/project-metadata-options\";\nimport { ClaudeRenderer } from \"./renderers/claude-renderer\";\nimport { CodexRenderer } from \"./renderers/codex-renderer\";\nimport { CopilotRenderer } from \"./renderers/copilot-renderer\";\nimport { CursorRenderer } from \"./renderers/cursor-renderer\";\nimport { resolveTemplateVariables } from \"./template-resolver\";\nimport {\n AGENT_PLATFORM,\n AGENT_RULE_SCOPE,\n AgentPlatform,\n AgentProcedure,\n AgentRule,\n AgentSkill,\n AgentSubAgent,\n} from \"./types\";\n\n/*******************************************************************************\n *\n * Default Claude Code permissions — hardened baseline that minimises approval\n * prompts while blocking destructive and dangerous operations.\n *\n * Projects can extend these via `claudeSettings.permissions.allow` /\n * `.deny` — user-supplied entries are appended (not replaced).\n *\n ******************************************************************************/\n\n/** @internal */\nconst DEFAULT_CLAUDE_ALLOW: ReadonlyArray<string> = [\n // ── Git ──────────────────────────────────────────────────────────────\n \"Bash(git add *)\",\n \"Bash(git branch *)\",\n \"Bash(git checkout *)\",\n \"Bash(git commit *)\",\n \"Bash(git diff *)\",\n \"Bash(git fetch *)\",\n \"Bash(git log *)\",\n \"Bash(git merge *)\",\n \"Bash(git mv *)\",\n \"Bash(git pull *)\",\n \"Bash(git push *)\",\n \"Bash(git rebase *)\",\n \"Bash(git rm *)\",\n \"Bash(git stash *)\",\n \"Bash(git status *)\",\n \"Bash(git show *)\",\n \"Bash(git rev-parse *)\",\n\n // ── GitHub CLI ───────────────────────────────────────────────────────\n \"Bash(gh issue *)\",\n \"Bash(gh pr *)\",\n \"Bash(gh repo *)\",\n \"Bash(gh api *)\",\n \"Bash(gh label *)\",\n \"Bash(gh run *)\",\n \"Bash(gh search *)\",\n \"Bash(gh browse *)\",\n \"Bash(gh status *)\",\n\n // ── Package manager ──────────────────────────────────────────────────\n \"Bash(pnpm *)\",\n\n // ── Read-only shell utilities ────────────────────────────────────────\n \"Bash(ls *)\",\n \"Bash(find *)\",\n \"Bash(cat *)\",\n \"Bash(head *)\",\n \"Bash(tail *)\",\n \"Bash(wc *)\",\n \"Bash(grep *)\",\n \"Bash(sort *)\",\n \"Bash(uniq *)\",\n \"Bash(dirname *)\",\n \"Bash(basename *)\",\n \"Bash(which *)\",\n \"Bash(diff *)\",\n \"Bash(jq *)\",\n \"Bash(date *)\",\n\n // ── Safe output / test utilities ─────────────────────────────────────\n \"Bash(echo *)\",\n \"Bash(printf *)\",\n \"Bash(test *)\",\n \"Bash([ *)\",\n \"Bash(true *)\",\n \"Bash(false *)\",\n\n // ── Safe directory operations ────────────────────────────────────────\n \"Bash(mkdir *)\",\n \"Bash(rmdir *)\",\n\n // ── Built-in tools ───────────────────────────────────────────────────\n \"Read(/**)\",\n \"Edit(/**)\",\n \"Write(/**)\",\n \"WebFetch\",\n \"WebSearch\",\n];\n\n/** @internal */\nconst DEFAULT_CLAUDE_DENY: ReadonlyArray<string> = [\n // ── Destructive git ──────────────────────────────────────────────────\n \"Bash(git push --force *)\",\n \"Bash(git push -f *)\",\n \"Bash(git push origin --force *)\",\n \"Bash(git push origin -f *)\",\n \"Bash(git reset --hard *)\",\n \"Bash(git clean -f *)\",\n \"Bash(git remote *)\",\n\n // ── Destructive file operations ──────────────────────────────────────\n \"Bash(rm -rf *)\",\n \"Bash(rm -r *)\",\n \"Bash(rm *)\",\n\n // ── Network / remote access ──────────────────────────────────────────\n \"Bash(curl *)\",\n \"Bash(wget *)\",\n \"Bash(ssh *)\",\n \"Bash(scp *)\",\n\n // ── System administration ────────────────────────────────────────────\n \"Bash(sudo *)\",\n \"Bash(chmod *)\",\n \"Bash(chown *)\",\n \"Bash(kill *)\",\n \"Bash(killall *)\",\n \"Bash(pkill *)\",\n\n // ── Code execution / shell spawning ──────────────────────────────────\n \"Bash(eval *)\",\n \"Bash(exec *)\",\n \"Bash(source *)\",\n \"Bash(. *)\",\n \"Bash(bash *)\",\n \"Bash(sh *)\",\n \"Bash(zsh *)\",\n\n // ── App launching ────────────────────────────────────────────────────\n \"Bash(open *)\",\n \"Bash(xdg-open *)\",\n\n // ── Environment manipulation ─────────────────────────────────────────\n \"Bash(export *)\",\n \"Bash(env *)\",\n];\n\n/**\n * Generates AI coding assistant configuration files from a common schema.\n *\n * Supports Cursor and Claude Code (initial release), with Codex and Copilot\n * renderers planned for future issues. Rules, skills, and sub-agents are\n * defined once and rendered into the correct format for each target platform.\n *\n * Follows the configulator component pattern: extends Component, static .of()\n * factory, options interface with JSDoc.\n *\n * @example\n * ```ts\n * new AgentConfig(project, {\n * rules: [{\n * name: 'my-rule',\n * description: 'Project conventions',\n * scope: AGENT_RULE_SCOPE.ALWAYS,\n * content: '# My Rule\\n\\nFollow these conventions...',\n * }],\n * });\n * ```\n */\nexport class AgentConfig extends Component {\n /**\n * Find the AgentConfig component on a project.\n */\n public static of(project: Project): AgentConfig | undefined {\n const isAgentConfig = (c: Component): c is AgentConfig =>\n c instanceof AgentConfig;\n return project.components.find(isAgentConfig);\n }\n\n /**\n * Merges default Claude permissions with bundle and user-supplied settings.\n *\n * Merge order: defaults → bundle permissions → user-supplied entries.\n * `defaultMode` defaults to `\"dontAsk\"` unless overridden.\n */\n private static mergeClaudeDefaults(\n userSettings?: ClaudeSettingsConfig,\n bundlePermissions?: { allow: Array<string>; deny: Array<string> },\n ): ClaudeSettingsConfig {\n const bundleAllow = bundlePermissions?.allow ?? [];\n const bundleDeny = bundlePermissions?.deny ?? [];\n const userAllow = userSettings?.permissions?.allow ?? [];\n const userDeny = userSettings?.permissions?.deny ?? [];\n\n return {\n ...userSettings,\n defaultMode: userSettings?.defaultMode ?? \"dontAsk\",\n permissions: {\n ...userSettings?.permissions,\n allow: [...DEFAULT_CLAUDE_ALLOW, ...bundleAllow, ...userAllow],\n deny: [...DEFAULT_CLAUDE_DENY, ...bundleDeny, ...userDeny],\n },\n };\n }\n\n private readonly options: AgentConfigOptions;\n\n constructor(project: Project, options: AgentConfigOptions = {}) {\n super(project);\n this.options = options;\n }\n\n /**\n * Returns the bundles that are active for this project: auto-detected\n * bundles (when `autoDetectBundles !== false`) plus force-included\n * bundles, minus explicitly excluded bundles. Deduplicated by name.\n *\n * Exposed so sibling components (e.g. the sync-labels workflow) can\n * consume bundle-contributed configuration.\n */\n public get activeBundles(): ReadonlyArray<AgentRuleBundle> {\n const bundleMap = new Map<string, AgentRuleBundle>();\n\n if (this.options.autoDetectBundles !== false) {\n for (const bundle of BUILT_IN_BUNDLES) {\n if (this.options.excludeBundles?.includes(bundle.name)) {\n continue;\n }\n if (bundle.name === \"base\" && this.options.includeBaseRules === false) {\n continue;\n }\n if (bundle.appliesWhen(this.project)) {\n bundleMap.set(bundle.name, bundle);\n }\n }\n }\n\n if (this.options.includeBundles) {\n for (const bundleName of this.options.includeBundles) {\n const bundle = BUILT_IN_BUNDLES.find((b) => b.name === bundleName);\n if (bundle) {\n bundleMap.set(bundle.name, bundle);\n }\n }\n }\n\n return [...bundleMap.values()];\n }\n\n public override preSynthesize(): void {\n super.preSynthesize();\n\n const platforms = this.resolvePlatforms();\n const rules = this.resolveRules();\n const skills = this.resolveSkills();\n const subAgents = this.resolveSubAgents();\n const procedures = this.resolveProcedures();\n const mcpServers = this.options.mcpServers ?? {};\n\n // Resolve template variables in rule content, skill instructions, and\n // sub-agent prompts using ProjectMetadata (if available).\n const projectMetadata = ProjectMetadata.of(this.project);\n const metadata = projectMetadata?.metadata;\n const resolvedRules = this.resolveTemplates(rules, metadata);\n const resolvedSkills = this.resolveSkillTemplates(skills, metadata);\n const resolvedSubAgents = this.resolveSubAgentTemplates(\n subAgents,\n metadata,\n );\n const resolvedProcedures = this.resolveProcedureTemplates(\n procedures,\n metadata,\n );\n\n if (platforms.includes(AGENT_PLATFORM.CURSOR)) {\n CursorRenderer.render(\n this,\n resolvedRules,\n resolvedSkills,\n resolvedSubAgents,\n mcpServers,\n this.options.cursorSettings,\n );\n }\n\n if (platforms.includes(AGENT_PLATFORM.CLAUDE)) {\n const bundlePermissions = this.resolveBundlePermissions();\n ClaudeRenderer.render(\n this,\n resolvedRules,\n resolvedSkills,\n resolvedSubAgents,\n mcpServers,\n AgentConfig.mergeClaudeDefaults(\n this.options.claudeSettings,\n bundlePermissions,\n ),\n resolvedProcedures,\n );\n }\n\n if (platforms.includes(AGENT_PLATFORM.CODEX)) {\n CodexRenderer.render(\n this,\n resolvedRules,\n resolvedSkills,\n resolvedSubAgents,\n );\n }\n\n if (platforms.includes(AGENT_PLATFORM.COPILOT)) {\n CopilotRenderer.render(\n this,\n resolvedRules,\n resolvedSkills,\n resolvedSubAgents,\n );\n }\n }\n\n private resolvePlatforms(): ReadonlyArray<AgentPlatform> {\n return (\n this.options.platforms ?? [AGENT_PLATFORM.CURSOR, AGENT_PLATFORM.CLAUDE]\n );\n }\n\n private resolveRules(): AgentRule[] {\n const ruleMap = new Map<string, AgentRule>();\n\n // 1. Auto-detected bundle rules\n if (this.options.autoDetectBundles !== false) {\n for (const bundle of BUILT_IN_BUNDLES) {\n if (this.options.excludeBundles?.includes(bundle.name)) continue;\n if (bundle.name === \"base\" && this.options.includeBaseRules === false) {\n continue;\n }\n if (bundle.appliesWhen(this.project)) {\n for (const rule of this.bundleRulesFor(bundle)) {\n ruleMap.set(rule.name, rule);\n }\n }\n }\n }\n\n // 2. Force-included bundles\n if (this.options.includeBundles) {\n for (const bundleName of this.options.includeBundles) {\n const bundle = BUILT_IN_BUNDLES.find((b) => b.name === bundleName);\n if (bundle) {\n for (const rule of this.bundleRulesFor(bundle)) {\n ruleMap.set(rule.name, rule);\n }\n }\n }\n }\n\n // 3. Custom rules (override bundle rules with same name)\n if (this.options.rules) {\n for (const rule of this.options.rules) {\n ruleMap.set(rule.name, rule);\n }\n }\n\n // 4. Remove excluded rules\n if (this.options.excludeRules) {\n for (const name of this.options.excludeRules) {\n ruleMap.delete(name);\n }\n }\n\n // 5. Apply rule extensions (append content to existing rules)\n if (this.options.ruleExtensions) {\n for (const [name, extra] of Object.entries(this.options.ruleExtensions)) {\n const existing = ruleMap.get(name);\n if (existing) {\n ruleMap.set(name, {\n ...existing,\n content: `${existing.content}\\n\\n---\\n\\n${extra}`,\n });\n }\n }\n }\n\n // 6. Sort: project-overview first, then by first tag (alphabetical), then by name\n return [...ruleMap.values()].sort((a, b) => {\n if (a.name === \"project-overview\") return -1;\n if (b.name === \"project-overview\") return 1;\n\n const tagA = a.tags?.[0] ?? \"\\uffff\";\n const tagB = b.tags?.[0] ?? \"\\uffff\";\n if (tagA !== tagB) return tagA.localeCompare(tagB);\n\n return a.name.localeCompare(b.name);\n });\n }\n\n /**\n * Return a bundle's rules with `filePatterns` narrowed to the projects\n * that actually matched the bundle's detection predicate (when the bundle\n * provides `findApplicableProjects`). Rules with `ALWAYS` scope and rules\n * on bundles that don't implement the hook are returned unchanged.\n */\n private bundleRulesFor(bundle: AgentRuleBundle): ReadonlyArray<AgentRule> {\n if (!bundle.findApplicableProjects) {\n return bundle.rules;\n }\n const detected = bundle.findApplicableProjects(this.project);\n if (detected.length === 0) {\n return bundle.rules;\n }\n const scoped = scopeFilePatternsToProjects(this.project, detected);\n return bundle.rules.map((rule) =>\n rule.scope === AGENT_RULE_SCOPE.FILE_PATTERN\n ? { ...rule, filePatterns: scoped }\n : rule,\n );\n }\n\n private resolveSkills(): AgentSkill[] {\n const skillMap = new Map<string, AgentSkill>();\n\n // 1. Auto-detected bundle skills\n if (this.options.autoDetectBundles !== false) {\n for (const bundle of BUILT_IN_BUNDLES) {\n if (this.options.excludeBundles?.includes(bundle.name)) continue;\n if (bundle.appliesWhen(this.project) && bundle.skills) {\n for (const skill of bundle.skills) {\n skillMap.set(skill.name, skill);\n }\n }\n }\n }\n\n // 2. Force-included bundle skills\n if (this.options.includeBundles) {\n for (const bundleName of this.options.includeBundles) {\n const bundle = BUILT_IN_BUNDLES.find((b) => b.name === bundleName);\n if (bundle?.skills) {\n for (const skill of bundle.skills) {\n skillMap.set(skill.name, skill);\n }\n }\n }\n }\n\n // 3. Custom skills (override)\n if (this.options.skills) {\n for (const skill of this.options.skills) {\n skillMap.set(skill.name, skill);\n }\n }\n\n return [...skillMap.values()];\n }\n\n private resolveSubAgents(): AgentSubAgent[] {\n const agentMap = new Map<string, AgentSubAgent>();\n\n // 1. Auto-detected bundle sub-agents\n if (this.options.autoDetectBundles !== false) {\n for (const bundle of BUILT_IN_BUNDLES) {\n if (this.options.excludeBundles?.includes(bundle.name)) continue;\n if (bundle.appliesWhen(this.project) && bundle.subAgents) {\n for (const agent of bundle.subAgents) {\n agentMap.set(agent.name, agent);\n }\n }\n }\n }\n\n // 2. Force-included bundle sub-agents\n if (this.options.includeBundles) {\n for (const bundleName of this.options.includeBundles) {\n const bundle = BUILT_IN_BUNDLES.find((b) => b.name === bundleName);\n if (bundle?.subAgents) {\n for (const agent of bundle.subAgents) {\n agentMap.set(agent.name, agent);\n }\n }\n }\n }\n\n // 3. Custom sub-agents (override)\n if (this.options.subAgents) {\n for (const agent of this.options.subAgents) {\n agentMap.set(agent.name, agent);\n }\n }\n\n return [...agentMap.values()];\n }\n\n private resolveProcedures(): AgentProcedure[] {\n const procMap = new Map<string, AgentProcedure>();\n\n // 1. Auto-detected bundle procedures\n if (this.options.autoDetectBundles !== false) {\n for (const bundle of BUILT_IN_BUNDLES) {\n if (this.options.excludeBundles?.includes(bundle.name)) continue;\n if (bundle.appliesWhen(this.project) && bundle.procedures) {\n for (const proc of bundle.procedures) {\n procMap.set(proc.name, proc);\n }\n }\n }\n }\n\n // 2. Force-included bundle procedures\n if (this.options.includeBundles) {\n for (const bundleName of this.options.includeBundles) {\n const bundle = BUILT_IN_BUNDLES.find((b) => b.name === bundleName);\n if (bundle?.procedures) {\n for (const proc of bundle.procedures) {\n procMap.set(proc.name, proc);\n }\n }\n }\n }\n\n // 3. Custom procedures (override)\n if (this.options.procedures) {\n for (const proc of this.options.procedures) {\n procMap.set(proc.name, proc);\n }\n }\n\n return [...procMap.values()];\n }\n\n /**\n * Resolves template variables in rule content using project metadata.\n * Emits synthesis warnings for rules with unresolved variables.\n */\n private resolveTemplates(\n rules: ReadonlyArray<AgentRule>,\n metadata: ResolvedProjectMetadata | undefined,\n ): ReadonlyArray<AgentRule> {\n return rules.map((rule) => {\n const { resolved, unresolvedKeys } = resolveTemplateVariables(\n rule.content,\n metadata,\n );\n if (unresolvedKeys.length > 0) {\n this.project.logger.warn(\n `AgentConfig: ProjectMetadata not found; rule '${rule.name}' using default values`,\n );\n }\n return resolved !== rule.content ? { ...rule, content: resolved } : rule;\n });\n }\n\n /**\n * Resolves template variables in skill instructions using project metadata.\n */\n private resolveSkillTemplates(\n skills: ReadonlyArray<AgentSkill>,\n metadata: ResolvedProjectMetadata | undefined,\n ): ReadonlyArray<AgentSkill> {\n return skills.map((skill) => {\n const { resolved, unresolvedKeys } = resolveTemplateVariables(\n skill.instructions,\n metadata,\n );\n if (unresolvedKeys.length > 0) {\n this.project.logger.warn(\n `AgentConfig: ProjectMetadata not found; skill '${skill.name}' using default values`,\n );\n }\n return resolved !== skill.instructions\n ? { ...skill, instructions: resolved }\n : skill;\n });\n }\n\n /**\n * Resolves template variables in sub-agent prompts using project metadata.\n */\n private resolveSubAgentTemplates(\n subAgents: ReadonlyArray<AgentSubAgent>,\n metadata: ResolvedProjectMetadata | undefined,\n ): ReadonlyArray<AgentSubAgent> {\n return subAgents.map((agent) => {\n const { resolved, unresolvedKeys } = resolveTemplateVariables(\n agent.prompt,\n metadata,\n );\n if (unresolvedKeys.length > 0) {\n this.project.logger.warn(\n `AgentConfig: ProjectMetadata not found; sub-agent '${agent.name}' using default values`,\n );\n }\n return resolved !== agent.prompt ? { ...agent, prompt: resolved } : agent;\n });\n }\n\n /**\n * Resolves template variables in procedure content using project metadata.\n */\n private resolveProcedureTemplates(\n procedures: ReadonlyArray<AgentProcedure>,\n metadata: ResolvedProjectMetadata | undefined,\n ): ReadonlyArray<AgentProcedure> {\n return procedures.map((proc) => {\n const { resolved, unresolvedKeys } = resolveTemplateVariables(\n proc.content,\n metadata,\n );\n if (unresolvedKeys.length > 0) {\n this.project.logger.warn(\n `AgentConfig: ProjectMetadata not found; procedure '${proc.name}' using default values`,\n );\n }\n return resolved !== proc.content ? { ...proc, content: resolved } : proc;\n });\n }\n\n /**\n * Collects Claude permission entries from all active bundles.\n */\n private resolveBundlePermissions(): {\n allow: Array<string>;\n deny: Array<string>;\n } {\n const allow: Array<string> = [];\n const deny: Array<string> = [];\n\n if (this.options.autoDetectBundles !== false) {\n for (const bundle of BUILT_IN_BUNDLES) {\n if (this.options.excludeBundles?.includes(bundle.name)) continue;\n if (bundle.appliesWhen(this.project) && bundle.claudePermissions) {\n if (bundle.claudePermissions.allow) {\n allow.push(...bundle.claudePermissions.allow);\n }\n if (bundle.claudePermissions.deny) {\n deny.push(...bundle.claudePermissions.deny);\n }\n }\n }\n }\n\n // Force-included bundles\n if (this.options.includeBundles) {\n for (const bundleName of this.options.includeBundles) {\n const bundle = BUILT_IN_BUNDLES.find((b) => b.name === bundleName);\n if (bundle?.claudePermissions) {\n if (bundle.claudePermissions.allow) {\n allow.push(...bundle.claudePermissions.allow);\n }\n if (bundle.claudePermissions.deny) {\n deny.push(...bundle.claudePermissions.deny);\n }\n }\n }\n }\n\n return { allow, deny };\n }\n}\n","/**\n * Defines the scope/activation model for an agent rule.\n * - ALWAYS: Rule is always active regardless of context\n * - FILE_PATTERN: Rule activates when the AI is working on files matching the patterns\n */\nexport const AGENT_RULE_SCOPE = {\n ALWAYS: \"always\",\n FILE_PATTERN: \"file-pattern\",\n} as const;\n\nexport type AgentRuleScope =\n (typeof AGENT_RULE_SCOPE)[keyof typeof AGENT_RULE_SCOPE];\n\n/**\n * Supported AI coding assistant platforms.\n */\nexport const AGENT_PLATFORM = {\n CURSOR: \"cursor\",\n CLAUDE: \"claude\",\n CODEX: \"codex\",\n COPILOT: \"copilot\",\n} as const;\n\nexport type AgentPlatform =\n (typeof AGENT_PLATFORM)[keyof typeof AGENT_PLATFORM];\n\n/**\n * Render target for Claude Code rules.\n * - SCOPED_FILE: .claude/rules/{name}.md (default — supports paths frontmatter for conditional activation)\n * - AGENTS_MD: AGENTS.md (always-active, shared with Codex)\n * - CLAUDE_MD: CLAUDE.md (always-active, Claude-only content not consumed by other agents)\n */\nexport const CLAUDE_RULE_TARGET = {\n SCOPED_FILE: \"scoped-file\",\n AGENTS_MD: \"agents-md\",\n CLAUDE_MD: \"claude-md\",\n} as const;\n\nexport type ClaudeRuleTarget =\n (typeof CLAUDE_RULE_TARGET)[keyof typeof CLAUDE_RULE_TARGET];\n\n/**\n * Model selection for sub-agents. Platforms map these to their own model identifiers.\n */\nexport const AGENT_MODEL = {\n INHERIT: \"inherit\",\n FAST: \"fast\",\n BALANCED: \"balanced\",\n POWERFUL: \"powerful\",\n} as const;\n\nexport type AgentModel = (typeof AGENT_MODEL)[keyof typeof AGENT_MODEL];\n\n/**\n * Maps abstract AGENT_MODEL values to Claude Code model aliases.\n * Returns undefined for \"inherit\" (omit the field entirely).\n * Cursor omits the model field to use its default model selection.\n */\nexport function resolveModelAlias(\n model: string | undefined,\n): string | undefined {\n if (!model || model === AGENT_MODEL.INHERIT) {\n return undefined;\n }\n const mapping: Record<string, string> = {\n [AGENT_MODEL.POWERFUL]: \"opus\",\n [AGENT_MODEL.BALANCED]: \"sonnet\",\n [AGENT_MODEL.FAST]: \"haiku\",\n };\n return mapping[model] ?? model;\n}\n\n/**\n * MCP server transport type.\n */\nexport const MCP_TRANSPORT = {\n STDIO: \"stdio\",\n HTTP: \"http\",\n SSE: \"sse\",\n} as const;\n\nexport type McpTransport = (typeof MCP_TRANSPORT)[keyof typeof MCP_TRANSPORT];\n\n/**\n * Platform-specific overrides for a rule.\n */\nexport interface AgentPlatformOverrides {\n /** Cursor-specific overrides */\n readonly cursor?: {\n /** Override the description used in Cursor's YAML frontmatter */\n readonly description?: string;\n /** Exclude this rule from Cursor output entirely */\n readonly exclude?: boolean;\n };\n /** Claude Code-specific overrides */\n readonly claude?: {\n /**\n * Where to render this rule for Claude Code.\n * - SCOPED_FILE: .claude/rules/{name}.md (default — supports paths frontmatter)\n * - AGENTS_MD: AGENTS.md (always-active, shared with Codex)\n * - CLAUDE_MD: CLAUDE.md (always-active, Claude-only)\n */\n readonly target?: ClaudeRuleTarget;\n /** Exclude this rule from Claude Code output entirely */\n readonly exclude?: boolean;\n };\n /** Codex-specific overrides (future) */\n readonly codex?: {\n /** Place this rule in a sub-directory AGENTS.md instead of root */\n readonly directory?: string;\n /** Exclude this rule from Codex output entirely */\n readonly exclude?: boolean;\n };\n /** Copilot-specific overrides (future) */\n readonly copilot?: {\n /** Exclude this rule from Copilot output entirely */\n readonly exclude?: boolean;\n };\n}\n\n/**\n * A single agent rule definition, platform-agnostic.\n */\nexport interface AgentRule {\n /**\n * Unique identifier for the rule. Used as the filename stem in platforms\n * that use per-rule files (Cursor, Claude Code, Copilot).\n * @example 'typescript-conventions'\n */\n readonly name: string;\n\n /**\n * Human-readable description of the rule's purpose.\n * Used by Cursor for AI-assisted rule selection.\n * @example 'TypeScript project patterns and conventions'\n */\n readonly description: string;\n\n /**\n * Activation scope for this rule.\n * - AGENT_RULE_SCOPE.ALWAYS: Active in all contexts\n * - AGENT_RULE_SCOPE.FILE_PATTERN: Active only when working on matching files\n */\n readonly scope: AgentRuleScope;\n\n /**\n * Glob patterns for conditional activation.\n * Required when scope is AGENT_RULE_SCOPE.FILE_PATTERN.\n * @example ['src/**\\/*.ts', 'tests/**\\/*.ts']\n */\n readonly filePatterns?: ReadonlyArray<string>;\n\n /**\n * The rule content as markdown. This is the platform-agnostic body\n * that applies equally to all AI assistants.\n */\n readonly content: string;\n\n /**\n * Optional per-platform overrides. Use sparingly — prefer platform-agnostic content.\n */\n readonly platforms?: AgentPlatformOverrides;\n\n /**\n * Optional tags for categorizing and ordering rules.\n * Rules are ordered by tag (alphabetical), then by name within each tag.\n * @example ['typescript', 'testing', 'workflow']\n */\n readonly tags?: ReadonlyArray<string>;\n}\n\n/**\n * A skill definition following the cross-platform Agent Skills specification.\n * Rendered to .claude/skills/ (Claude Code) and .cursor/skills/ (Cursor).\n */\nexport interface AgentSkill {\n /**\n * Unique identifier for the skill. Becomes the /slash-command name.\n * @example 'commit'\n */\n readonly name: string;\n\n /**\n * Human-readable description. Claude uses this to decide when to auto-invoke.\n */\n readonly description: string;\n\n /**\n * Multi-line instruction content (markdown). Becomes the SKILL.md body.\n */\n readonly instructions: string;\n\n /**\n * Optional tool allowlist for this skill.\n * @example ['Read', 'Bash(npm run *)']\n */\n readonly allowedTools?: ReadonlyArray<string>;\n\n /**\n * Whether to prevent auto-invocation of this skill.\n * When true, only triggered by the user typing /skill-name.\n * @default false\n */\n readonly disableModelInvocation?: boolean;\n\n /**\n * Whether the user can invoke this skill directly via /skill-name.\n * Set to false for background skills that should not appear in the / menu.\n * @default true\n */\n readonly userInvocable?: boolean;\n\n /**\n * Model override when this skill is active.\n * @example 'claude-opus-4-6'\n */\n readonly model?: string;\n\n /**\n * Reasoning effort level when this skill is active.\n * @example 'high'\n */\n readonly effort?: string;\n\n /**\n * Glob patterns that limit when the skill is auto-loaded.\n * @example ['src/api/**\\/*.ts']\n */\n readonly paths?: ReadonlyArray<string>;\n\n /**\n * Resource directories bundled with the skill (e.g., references/, scripts/, assets/).\n * Documentation hint only — directory names listed here are not emitted to disk.\n * Prefer {@link referenceFiles} to ship actual companion file contents.\n *\n * @deprecated Use {@link referenceFiles} to emit physical companion files.\n * @example ['references/', 'scripts/']\n */\n readonly references?: ReadonlyArray<string>;\n\n /**\n * Companion files shipped alongside the SKILL.md (e.g., templates, references, scripts).\n * Each entry is rendered as a TextFile under the skill's directory on every\n * platform that emits skills (Claude: `.claude/skills/{name}/{path}`,\n * Cursor: `.cursor/skills/{name}/{path}`).\n *\n * Use this for skill assets that benefit from being separate files rather than\n * inlined into the skill instructions — large templates, reference tables,\n * runnable scripts.\n *\n * Per-platform `platforms.{claude,cursor}.exclude` flags suppress reference\n * files for that platform alongside the SKILL.md.\n *\n * @example\n * referenceFiles: [\n * { path: '_references/templates/_template-FR.md', content: '# Functional Requirement\\n...' },\n * { path: '_references/standards-and-frameworks.md', content: '# Standards\\n...' },\n * ]\n */\n readonly referenceFiles?: ReadonlyArray<{\n /** Path relative to the skill directory (e.g., `_references/templates/_template-FR.md`). */\n readonly path: string;\n /** File contents written verbatim. */\n readonly content: string;\n }>;\n\n /**\n * Context isolation mode. Set to 'fork' to run in an isolated subagent context.\n */\n readonly context?: string;\n\n /**\n * Subagent name to delegate to when context is 'fork'.\n * @example 'code-reviewer'\n */\n readonly agent?: string;\n\n /**\n * Shell for dynamic context injection via !`command` syntax.\n * @default 'bash'\n */\n readonly shell?: string;\n\n /** Per-platform overrides. Use `exclude: true` to skip a platform. */\n readonly platforms?: {\n readonly claude?: { readonly exclude?: boolean };\n readonly cursor?: { readonly exclude?: boolean };\n };\n}\n\n/**\n * Platform-specific overrides for a sub-agent definition.\n */\n/**\n * Copilot handoff definition for sub-agent delegation.\n */\nexport interface CopilotHandoff {\n /** Display label for the handoff action. */\n readonly label: string;\n /** Target agent name. */\n readonly agent: string;\n /** Optional prompt to pass to the target agent. */\n readonly prompt?: string;\n /** Whether to auto-send the handoff without user confirmation. */\n readonly send?: boolean;\n}\n\nexport interface AgentSubAgentPlatformOverrides {\n /** Claude Code-specific overrides */\n readonly claude?: {\n /** Permission mode: default, acceptEdits, dontAsk, bypassPermissions, plan */\n readonly permissionMode?: string;\n /** Run in isolated git worktree */\n readonly isolation?: string;\n /** Run as a background task */\n readonly background?: boolean;\n /** Reasoning effort level (Opus): low, medium, high, max */\n readonly effort?: string;\n /** Persistent memory scope: user, project, local */\n readonly memory?: string;\n /** Exclude this sub-agent from Claude Code output entirely */\n readonly exclude?: boolean;\n };\n /** Cursor-specific overrides */\n readonly cursor?: {\n /** Restrict the sub-agent to read-only operations */\n readonly readonly?: boolean;\n /** Run the sub-agent asynchronously as a background task */\n readonly isBackground?: boolean;\n /** Exclude this sub-agent from Cursor output entirely */\n readonly exclude?: boolean;\n };\n /** Codex-specific overrides (future) */\n readonly codex?: {\n /** Sandbox mode: read-only or full */\n readonly sandboxMode?: string;\n /** Model reasoning effort */\n readonly modelReasoningEffort?: string;\n /** Exclude this sub-agent from Codex output entirely */\n readonly exclude?: boolean;\n };\n /** Copilot-specific overrides (future) */\n readonly copilot?: {\n /** Target environment: vscode or github-copilot */\n readonly target?: string;\n /** Whether the user can invoke this sub-agent directly */\n readonly userInvocable?: boolean;\n /** Prevent auto-invocation of this sub-agent */\n readonly disableModelInvocation?: boolean;\n /** Handoff definitions for agent-to-agent delegation */\n readonly handoffs?: ReadonlyArray<CopilotHandoff>;\n /** Exclude this sub-agent from Copilot output entirely */\n readonly exclude?: boolean;\n };\n}\n\n/**\n * A custom sub-agent definition, platform-agnostic.\n * Rendered to .cursor/agents/ (Cursor), .claude/agents/ (Claude Code).\n */\nexport interface AgentSubAgent {\n /**\n * Unique identifier for the sub-agent. Used as the filename stem.\n * Must be lowercase letters and hyphens only.\n * @example 'code-reviewer'\n */\n readonly name: string;\n\n /** Human-readable description. Used by the parent agent to decide when to delegate. */\n readonly description: string;\n\n /**\n * System prompt / instructions for the sub-agent (markdown).\n * This becomes the body of the generated agent file.\n */\n readonly prompt: string;\n\n /**\n * Model selection for this sub-agent.\n * @default AGENT_MODEL.INHERIT\n */\n readonly model?: AgentModel;\n\n /**\n * Tool allowlist. When omitted, inherits all tools from parent.\n * @example ['Read', 'Glob', 'Grep']\n */\n readonly tools?: ReadonlyArray<string>;\n\n /**\n * Tool denylist. Applied before the allowlist.\n * @example ['Bash', 'Write']\n */\n readonly disallowedTools?: ReadonlyArray<string>;\n\n /** Maximum agentic turns before the sub-agent stops. */\n readonly maxTurns?: number;\n\n /**\n * Skills to preload for this sub-agent.\n * @example ['commit', 'review-pr']\n */\n readonly skills?: ReadonlyArray<string>;\n\n /**\n * MCP servers available to this sub-agent.\n * Rendered to the platform-specific sub-agent config.\n */\n readonly mcpServers?: Readonly<Record<string, McpServerConfig>>;\n\n /**\n * Sub-agents this agent can invoke/delegate to.\n * @example ['test-writer', 'code-reviewer']\n */\n readonly canDelegateToAgents?: ReadonlyArray<string>;\n\n /** Optional per-platform overrides for this sub-agent. */\n readonly platforms?: AgentSubAgentPlatformOverrides;\n}\n\n/**\n * An executable procedure (shell script) that ships with a bundle.\n * Rendered to .claude/procedures/{name} as an executable file.\n */\nexport interface AgentProcedure {\n /**\n * Filename for the procedure (e.g., 'check-blocked.sh').\n * Used as the filename in .claude/procedures/.\n */\n readonly name: string;\n\n /** Human-readable description of what this procedure does. */\n readonly description: string;\n\n /** Script content as a single string. Lines are split on newlines for rendering. */\n readonly content: string;\n}\n\n/**\n * MCP server configuration. Cross-platform — rendered to .claude/settings.json\n * (Claude Code) and .cursor/mcp.json (Cursor).\n */\nexport interface McpServerConfig {\n /**\n * Transport type for the server connection.\n * @default MCP_TRANSPORT.STDIO\n */\n readonly transport?: McpTransport;\n\n /** Command to launch a stdio server. */\n readonly command?: string;\n\n /** Command arguments for stdio server. */\n readonly args?: ReadonlyArray<string>;\n\n /** URL for HTTP/SSE remote servers. */\n readonly url?: string;\n\n /** HTTP headers for HTTP/SSE connections. */\n readonly headers?: Readonly<Record<string, string>>;\n\n /** Environment variables for the server process. */\n readonly env?: Readonly<Record<string, string>>;\n\n /**\n * Tool allowlist — only these tools from the server will be available.\n * @example ['read_file', 'search']\n */\n readonly enabledTools?: ReadonlyArray<string>;\n\n /**\n * Tool denylist — these tools from the server will be blocked.\n * Applied before enabledTools.\n * @example ['delete_file', 'execute']\n */\n readonly disabledTools?: ReadonlyArray<string>;\n}\n","import { Component, Project } from \"projen/lib\";\n\n/**\n * Return the project and/or subprojects that have a component of a given type.\n * Walks one level of subprojects (does not recurse into sub-subprojects).\n */\nexport function findProjectsWithComponent<T extends Component>(\n project: Project,\n ctor: new (...args: any[]) => T,\n): Array<Project> {\n const out: Array<Project> = [];\n if (project.components.some((c) => c instanceof ctor)) {\n out.push(project);\n }\n for (const sub of project.subprojects) {\n if (sub.components.some((c) => c instanceof ctor)) {\n out.push(sub);\n }\n }\n return out;\n}\n\n/**\n * Return the project and/or subprojects that declare a dependency with the\n * given name. Walks one level of subprojects.\n */\nexport function findProjectsWithDep(\n project: Project,\n name: string,\n): Array<Project> {\n const out: Array<Project> = [];\n if (project.deps.all.some((d) => d.name === name)) {\n out.push(project);\n }\n for (const sub of project.subprojects) {\n if (sub.deps.all.some((d) => d.name === name)) {\n out.push(sub);\n }\n }\n return out;\n}\n\n/**\n * Return the project and/or subprojects that contain a file with the given\n * name. Walks one level of subprojects.\n */\nexport function findProjectsWithFile(\n project: Project,\n filename: string,\n): Array<Project> {\n const out: Array<Project> = [];\n if (project.tryFindFile(filename) !== undefined) {\n out.push(project);\n }\n for (const sub of project.subprojects) {\n if (sub.tryFindFile(filename) !== undefined) {\n out.push(sub);\n }\n }\n return out;\n}\n\n/**\n * Check whether a component of a given type exists on the project or any subproject.\n */\nexport function hasComponent<T extends Component>(\n project: Project,\n ctor: new (...args: any[]) => T,\n): boolean {\n return findProjectsWithComponent(project, ctor).length > 0;\n}\n\n/**\n * Check whether a dependency exists on the project or any subproject.\n */\nexport function hasDep(project: Project, name: string): boolean {\n return findProjectsWithDep(project, name).length > 0;\n}\n\n/**\n * Check whether a file exists on the project or any subproject.\n */\nexport function hasFile(project: Project, filename: string): boolean {\n return findProjectsWithFile(project, filename).length > 0;\n}\n","import { Project } from \"projen/lib\";\nimport { AgentRuleBundle } from \"../agent-config-options\";\nimport { AGENT_RULE_SCOPE } from \"../types\";\nimport { findProjectsWithDep, hasDep } from \"./utils\";\n\n/**\n * AWS CDK bundle — auto-detected when `aws-cdk-lib` is in dependencies.\n */\nexport const awsCdkBundle: AgentRuleBundle = {\n name: \"aws-cdk\",\n description:\n \"AWS CDK construct patterns, L2/L3 conventions, IAM best practices\",\n appliesWhen: (project: Project) => hasDep(project, \"aws-cdk-lib\"),\n findApplicableProjects: (project: Project) =>\n findProjectsWithDep(project, \"aws-cdk-lib\"),\n rules: [\n {\n name: \"aws-cdk-conventions\",\n description: \"AWS CDK construct patterns and best practices\",\n scope: AGENT_RULE_SCOPE.FILE_PATTERN,\n filePatterns: [\"**/*.ts\"],\n content: [\n \"# AWS CDK Conventions\",\n \"\",\n \"## Construct Structure\",\n \"\",\n \"- All constructs extend `Construct` from `constructs`\",\n \"- Use `readonly` for all props interfaces\",\n \"- Include minimal JSDoc for configuration options\",\n \"- Follow AWS CDK best practices for resource naming and organization\",\n \"- Use proper TypeScript types from `aws-cdk-lib`\",\n \"- Export constructs from `index.ts` for public API\",\n \"\",\n \"## CDK Construct Pattern\",\n \"\",\n \"```typescript\",\n \"export interface MyConstructProps {\",\n \" /** Brief description. */\",\n \" readonly myProperty: string;\",\n \"}\",\n \"\",\n \"export class MyConstruct extends Construct {\",\n \" constructor(scope: Construct, id: string, props: MyConstructProps) {\",\n \" super(scope, id);\",\n \" // Implementation\",\n \" }\",\n \"}\",\n \"```\",\n \"\",\n \"## L2 Over L1 Construct Preference\",\n \"\",\n \"- Always prefer L2 constructs (e.g., `s3.Bucket`, `lambda.Function`) over L1 escape hatches (`CfnBucket`, `CfnFunction`)\",\n \"- Only drop to L1 when the L2 construct is missing the feature you need or does not exist yet\",\n \"- When using L1, add a comment explaining why the L2 was insufficient\",\n \"\",\n \"## Filename / Class Name Matching\",\n \"\",\n \"- Kebab-case filenames must mirror PascalCase class names (e.g., `my-construct.ts` → `MyConstruct`)\",\n \"- Name props interfaces `ClassNameProps` (e.g., `MyConstructProps`)\",\n \"- One primary construct per file; supporting types (props interface, enums) live in the same file\",\n \"- Test files follow the same pattern: `my-construct.spec.ts`\",\n \"- When renaming, prefer renaming the class to match the filename\",\n \"\",\n \"## Cross-Stack Lookup Patterns\",\n \"\",\n \"- Lookups live on **service classes**, not component/construct classes — do not add `fromConstruct()` or similar lookup methods to component classes\",\n \"- Use `*.of(this)` for stack or service references where the pattern exists in the codebase\",\n \"- Within services, prefer creating resources in protected methods; expose retrieval via static methods on the owning service\",\n \"- Use static methods for cross-stack lookups so consumers don't need an instance:\",\n \"\",\n \"```typescript\",\n \"export class MyService {\",\n \" /** Look up a resource from another stack via SSM. */\",\n \" public static lookupArn(scope: Construct, id: string): string {\",\n \" return StringParameter.valueForStringParameter(\",\n \" scope,\",\n \" `/my-app/my-resource-arn`,\",\n \" );\",\n \" }\",\n \"}\",\n \"```\",\n \"\",\n \"- Store outputs in SSM parameters with well-known paths; do not pass values between stacks via props\",\n \"\",\n \"## AWS Best Practices\",\n \"\",\n \"- Use AWS CDK v2 (`aws-cdk-lib`)\",\n \"- Follow AWS best practices for security and resource configuration\",\n \"- Use proper IAM permissions (principle of least privilege)\",\n \"- Include proper tags and descriptions for resources\",\n \"- Use SSM parameters for cross-stack references when needed\",\n \"- Do not pass values between stacks; use SSM parameters instead\",\n \"\",\n \"## Lambda Handlers (NodejsFunction)\",\n \"\",\n \"- When adding a `NodejsFunction` with a bundled handler, ensure the `entry` path is explicitly configured\",\n \"- Verify the entry is included in the build tool config (e.g., tsup entry list) so the runtime can find the handler\",\n \"\",\n \"## CDK Testing\",\n \"\",\n \"- Mock `Code.fromAsset` in any test file that synthesizes CDK stacks\",\n \"- Use static S3 values (`mock-assets-bucket`, `mock-asset-key.zip`) so snapshots are stable\",\n \"- Add the mock in `beforeAll` and restore in `afterAll`:\",\n \"\",\n \"```typescript\",\n \"let fromAssetMock: MockInstance;\",\n \"\",\n \"beforeAll(() => {\",\n ' fromAssetMock = vi.spyOn(Code, \"fromAsset\").mockReturnValue({',\n \" isInline: false,\",\n \" bind: () => ({\",\n \" s3Location: {\",\n ' bucketName: \"mock-assets-bucket\",',\n ' objectKey: \"mock-asset-key.zip\",',\n \" },\",\n \" }),\",\n \" bindToResource: () => {},\",\n \" } as unknown as AssetCode);\",\n \"});\",\n \"\",\n \"afterAll(() => {\",\n \" fromAssetMock.mockRestore();\",\n \"});\",\n \"```\",\n \"\",\n \"- Normalize the template before snapshotting when the stack includes asset-based Lambdas\",\n \"- Use `Template.fromStack(stack)` and assert with `hasResourceProperties` for targeted checks\",\n ].join(\"\\n\"),\n tags: [\"infrastructure\"],\n },\n ],\n};\n","import { AgentRuleBundle } from \"../agent-config-options\";\nimport { AGENT_RULE_SCOPE, AgentSkill } from \"../types\";\n\nconst createRuleSkill: AgentSkill = {\n name: \"create-rule\",\n description:\n \"Guide for creating new agent rules in this project using configulator\",\n disableModelInvocation: true,\n instructions: [\n \"# Create Agent Rule\",\n \"\",\n \"Create a new agent rule for the **{{repository.owner}}/{{repository.name}}** project.\",\n \"\",\n \"## Steps\",\n \"\",\n \"1. **Identify the rule purpose** — ask what behavior the rule should enforce or guide\",\n \"2. **Choose a scope:**\",\n \" - `AGENT_RULE_SCOPE.ALWAYS` — active in all contexts\",\n \" - `AGENT_RULE_SCOPE.FILE_PATTERN` — active only when working on matching files (requires `filePatterns`)\",\n \"3. **Pick a name** — lowercase kebab-case (e.g., `react-conventions`, `api-error-handling`)\",\n \"4. **Write the content** — clear, actionable markdown instructions\",\n \"5. **Add to the project config** — add the rule to `AgentConfigOptions.rules` in the Projen config file\",\n \"\",\n \"## Rule Template\",\n \"\",\n \"```typescript\",\n \"import { AGENT_RULE_SCOPE } from '@codedrifters/configulator';\",\n \"\",\n \"// In your AgentConfig options:\",\n \"{\",\n \" rules: [\",\n \" {\",\n \" name: 'my-new-rule',\",\n \" description: 'What this rule does — used by AI for rule selection',\",\n \" scope: AGENT_RULE_SCOPE.ALWAYS, // or FILE_PATTERN\",\n \" // filePatterns: ['src/**/*.ts'], // required for FILE_PATTERN scope\",\n \" content: [\",\n \" '# Rule Title',\",\n \" '',\",\n \" '## Guidelines',\",\n \" '',\",\n \" '- Guideline 1',\",\n \" '- Guideline 2',\",\n \" ].join('\\\\n'),\",\n \" tags: ['coding'], // optional: for ordering\",\n \" },\",\n \" ],\",\n \"}\",\n \"```\",\n \"\",\n \"## Best Practices\",\n \"\",\n \"- Keep rules **focused** — one concern per rule\",\n '- Use **imperative tone** — \"Use X\" not \"You should use X\"',\n \"- Include **examples** for complex patterns\",\n \"- Use `ruleExtensions` to add project-specific content to existing bundle rules instead of replacing them\",\n ].join(\"\\n\"),\n};\n\n/**\n * Base bundle — always included unless `includeBaseRules: false`.\n * Contains project-overview, interaction-style, and general-conventions rules.\n */\nexport const baseBundle: AgentRuleBundle = {\n name: \"base\",\n description:\n \"Core rules: project overview, interaction style, and general coding conventions\",\n appliesWhen: () => true,\n skills: [createRuleSkill],\n rules: [\n {\n name: \"project-overview\",\n description: \"Project context and technology stack overview\",\n scope: AGENT_RULE_SCOPE.ALWAYS,\n content: [\n \"# Project Overview\",\n \"\",\n \"**Repository:** {{repository.owner}}/{{repository.name}}\",\n \"**Default branch:** {{repository.defaultBranch}}\",\n \"\",\n \"## Important Notes\",\n \"\",\n \"- **Never edit generated files** — they are marked with `// ~~ Generated by projen`\",\n \"- **After modifying Projen configuration**, run `npx projen` to regenerate files, then `pnpm install` to update the lockfile.\",\n \"- **Configure dependencies through Projen** — never use `npm install`, `pnpm add`, or `yarn add`. Add them to `deps` or `devDeps` in Projen config.\",\n \"- **Export from index.ts** to maintain clean public APIs\",\n ].join(\"\\n\"),\n tags: [\"project\"],\n },\n {\n name: \"cursor-projen-restrictions\",\n description:\n \"Cursor must not run projen, build, test, or package-manager commands\",\n scope: AGENT_RULE_SCOPE.ALWAYS,\n content: [\n \"# Projen & Development Command Restrictions\",\n \"\",\n \"**Never** run any of the following commands. Instead, tell the user which commands to run and why.\",\n \"\",\n \"## Prohibited Commands\",\n \"\",\n \"- `npx projen` — synthesize project files\",\n \"- `pnpm install` / `pnpm i` — install dependencies\",\n \"- `pnpm build` / `pnpm build:all` — build the project\",\n \"- `pnpm test` / `pnpm --filter ... test` — run tests\",\n \"- `pnpm eslint` / `pnpm --filter ... eslint` — run linting\",\n \"- `pnpm compile` / `pnpm --filter ... compile` — compile packages\",\n \"- `pnpm reset` / `pnpm reset:all` — reset build artifacts\",\n \"- Any `vitest`, `tsup`, `rollup`, or `turbo` commands\",\n \"\",\n \"## What to Do Instead\",\n \"\",\n \"After making changes that need validation, tell the user the specific commands to run:\",\n \"\",\n \"1. **After projen config changes** — tell the user to run `npx projen && pnpm install`\",\n \"2. **After source code changes** — tell the user to run `pnpm --filter @codedrifters/<package> test`\",\n \"3. **After multi-package changes** — tell the user to run `pnpm build:all`\",\n ].join(\"\\n\"),\n platforms: {\n claude: { exclude: true },\n },\n tags: [\"project\"],\n },\n {\n name: \"reference-documentation\",\n description:\n \"Consult project rules, documentation, and existing code before answering or making changes\",\n scope: AGENT_RULE_SCOPE.ALWAYS,\n content: [\n \"# Reference Documentation\",\n \"\",\n \"Before answering questions or making changes, always consult available project context.\",\n \"\",\n \"1. **Read project rules and guidelines** — check for agent rules, contribution guides, and coding standards defined in the project.\",\n \"2. **Review existing code** — understand current patterns, conventions, and architecture before proposing changes. Look at similar files and modules for reference.\",\n \"3. **Check documentation** — consult README files, inline documentation, and any design documents for relevant context.\",\n \"4. **Respect established patterns** — follow the conventions already in use rather than introducing new ones without discussion.\",\n \"5. **Verify before assuming** — if documentation or code conflicts with your assumptions, trust the project sources and ask for clarification when needed.\",\n ].join(\"\\n\"),\n tags: [\"project\"],\n },\n {\n name: \"interaction-style\",\n description:\n \"Interaction style — ask questions one at a time and wait for feedback\",\n scope: AGENT_RULE_SCOPE.ALWAYS,\n content: [\n \"# Interaction Style Guidelines\",\n \"\",\n \"When responding to requests, follow these interaction principles.\",\n \"\",\n \"1. **Ask when ambiguous**: When requirements are ambiguous or incomplete, always ask clarifying questions before proceeding. Do not make assumptions about the user's intent — it is better to ask than to guess wrong.\",\n \"2. **Ask questions one at a time**: When clarification is needed, ask a single question and wait for the user's response before proceeding.\",\n \"3. **Wait for feedback**: After asking a question, pause and wait for the user's answer before asking additional questions or making assumptions.\",\n \"4. **Avoid question overload**: Do not ask multiple questions in a single response. If multiple clarifications are needed, prioritize the most important question first.\",\n \"5. **Progressive clarification**: Once the user answers your first question, you may then ask the next most important question if needed.\",\n \"6. **Confirm understanding**: After receiving feedback, acknowledge the user's response before proceeding with the next step or question.\",\n \"7. **Be patient**: Do not rush ahead with assumptions. It is better to ask one clarifying question than to proceed with incorrect assumptions.\",\n ].join(\"\\n\"),\n tags: [\"project\"],\n },\n {\n name: \"general-conventions\",\n description:\n \"Code formatting (Prettier/ESLint), import conventions (ES modules, import order), error handling (async/await, no floating promises)\",\n scope: AGENT_RULE_SCOPE.FILE_PATTERN,\n filePatterns: [\"**/*.ts\", \"**/*.tsx\"],\n content: [\n \"# General Conventions\",\n \"\",\n \"## Code Formatting\",\n \"\",\n \"- Use **Prettier** for formatting (runs automatically on save in VS Code)\",\n \"- Always use curly braces for control flow, even single-line statements; use multi-line format for complex conditionals\",\n \"- Prefer `const` over `let`; avoid `var`\",\n \"- Use trailing commas in multi-line objects/arrays\",\n \"\",\n \"### ESLint Rules to Follow\",\n \"\",\n \"- `curly`: Always use curly braces (multi-line, consistent)\",\n \"- `dot-notation`: Use dot notation over bracket notation\",\n \"- `no-bitwise`: No bitwise operators\",\n \"- `@typescript-eslint/no-shadow`: No variable shadowing\",\n \"- `@typescript-eslint/member-ordering`: Follow member order\",\n \"\",\n \"## Import Conventions\",\n \"\",\n \"- **Always use ES modules** (`import`/`export`), never `require()` (exception: `.projenrc.ts` files where `require` is allowed)\",\n \"- Import order:\",\n \" 1. Built-in Node.js modules (e.g., `node:path`, `node:fs`)\",\n \" 2. External dependencies (alphabetically sorted)\",\n \" 3. Internal imports (relative paths)\",\n \"- Group imports with blank lines between groups\",\n \"- Alphabetize imports within each group (case-insensitive)\",\n \"- Use absolute imports from package root when possible\",\n \"- Avoid duplicate imports (`import/no-duplicates`); all imports must be resolvable (`import/no-unresolved`)\",\n \"\",\n \"## Error Handling\",\n \"\",\n \"- Always handle promises properly with `await`\",\n \"- Use `@typescript-eslint/return-await` rule (always return await)\",\n \"- Never leave floating promises (`@typescript-eslint/no-floating-promises`)\",\n \"- Use proper error types and meaningful error messages\",\n \"- Do not swallow errors or use empty catch blocks\",\n \"- Prefer async/await over raw promises\",\n ].join(\"\\n\"),\n tags: [\"coding\"],\n },\n {\n name: \"pull-request-conventions\",\n description:\n \"Conventional commit PR titles, closing keywords, change summaries\",\n scope: AGENT_RULE_SCOPE.ALWAYS,\n content: [\n \"# Pull Request Conventions\",\n \"\",\n \"## PR Title Prefix\",\n \"\",\n \"**Always** use a **conventional commit prefix** in the PR `title`. Format: `type: description` or `type(scope): description`.\",\n \"\",\n \"| Prefix | Use for |\",\n \"|--------|---------|\",\n \"| `feat:` | New features or functionality |\",\n \"| `fix:` | Bug fixes |\",\n \"| `docs:` | Documentation-only changes |\",\n \"| `chore:` | Maintenance: deps, tooling, config |\",\n \"| `refactor:` | Code restructure, no behavior change |\",\n \"| `release:` | Release preparation, version bumps |\",\n \"| `hotfix:` | Urgent production fixes |\",\n \"\",\n \"## Link to the Issue\",\n \"\",\n \"When the PR addresses an issue, **always** include a closing keyword in the PR body:\",\n \"- `Closes #<issue>`, `Fixes #<issue>`, or `Resolves #<issue>`\",\n \"\",\n \"## Summary of Changes\",\n \"\",\n \"Every PR must include a **summary of the changes** made. Use bullet points or short paragraphs. Do not leave the description empty.\",\n \"\",\n \"## Commit Messages\",\n \"\",\n \"Use **conventional commits** for git commit messages: `type: short description`. Do not add AI co-author or attribution.\",\n ].join(\"\\n\"),\n tags: [\"workflow\"],\n },\n {\n name: \"branch-naming-conventions\",\n description:\n \"Branch format (type/issue-description), create-on-GitHub-then-fetch workflow\",\n scope: AGENT_RULE_SCOPE.ALWAYS,\n content: [\n \"# Branch Naming Conventions\",\n \"\",\n \"## Format\",\n \"\",\n \"```\",\n \"<type>/<issue-number>-<issue-slug>\",\n \"```\",\n \"\",\n \"- **type** (required): One of `feat`, `fix`, `docs`, `chore`, `refactor`, `release`, `hotfix`\",\n \"- **issue-number** (required): The GitHub issue number (e.g., `25`)\",\n \"- **issue-slug** (required): Short, lowercase, kebab-case summary derived from the issue title\",\n \"\",\n \"## Examples\",\n \"\",\n \"- `feat/25-add-cursor-rules`\",\n \"- `fix/23-rename-cursor-rules-mdc`\",\n \"- `chore/42-upgrade-eslint`\",\n \"- `docs/18-update-readme`\",\n ].join(\"\\n\"),\n tags: [\"workflow\"],\n },\n {\n name: \"issue-label-conventions\",\n description:\n \"Priority and status label taxonomy, defaults, inference rules, and blocking rules for agent-created or updated issues\",\n scope: AGENT_RULE_SCOPE.ALWAYS,\n content: [\n \"# Issue Label Conventions\",\n \"\",\n \"Every issue created or updated by an agent in **{{repository.owner}}/{{repository.name}}**\",\n \"must carry exactly one `priority:*` label and exactly one `status:*` label.\",\n \"These conventions apply to **all** agent bundles — do not redefine them\",\n \"locally. The orchestrator and issue worker depend on this taxonomy.\",\n \"\",\n \"## Priority Labels\",\n \"\",\n \"Pick exactly one of the following:\",\n \"\",\n \"| Label | Criteria |\",\n \"|-------|----------|\",\n \"| `priority:critical` | Production is broken, blocked, or data at risk. Must start immediately. Use for outages, security incidents, regressions that block a release. |\",\n \"| `priority:high` | Important work that should be next in the queue. Blocks other planned work, an epic's children, or a near-term deliverable. |\",\n \"| `priority:medium` | Default for normal planned work. No immediate blocker but belongs in the current roadmap. |\",\n \"| `priority:low` | Nice-to-have. Can be deferred without impact. Cleanups, minor polish, non-urgent refactors. |\",\n \"| `priority:trivial` | Cosmetic or optional. Typos, formatting, stray comments. Safe to never pick up. |\",\n \"\",\n \"### Default Priority\",\n \"\",\n \"When the user has not indicated a priority and context provides no signal,\",\n \"assign `priority:medium`.\",\n \"\",\n \"### Inference Heuristics\",\n \"\",\n \"Before defaulting to medium, scan the user's request and the issue context\",\n \"for these signals:\",\n \"\",\n \"- **Urgency language** — words like *urgent*, *ASAP*, *immediately*, *now*,\",\n \" *blocker*, *on fire* → `priority:critical`\",\n \"- **Importance language** — words like *important*, *soon*, *need this*,\",\n \" *next up*, *before launch* → `priority:high`\",\n \"- **Deadlines** — an explicit due date within 7 days → `priority:high`;\",\n \" within 24 hours or labeled as a release blocker → `priority:critical`\",\n \"- **Blocker status** — the issue blocks another open issue, an epic child,\",\n \" or a release → `priority:high` (or `priority:critical` if the blocked\",\n \" work is itself critical)\",\n \"- **Business impact** — revenue loss, customer-facing outage, security\",\n \" exposure → `priority:critical`\",\n \"- **Polish language** — *nice to have*, *minor*, *cleanup*, *whenever*,\",\n \" *low priority* → `priority:low`\",\n \"- **Cosmetic scope** — typo fixes, comment tweaks, formatting-only → `priority:trivial`\",\n \"- **Meeting-note origin** — any issue created from reviewing meeting notes or\",\n \" a meeting transcript → `priority:high` (meeting follow-ups are time-sensitive\",\n \" and presumed important unless the note explicitly says otherwise)\",\n \"\",\n \"### Ask vs. Infer\",\n \"\",\n \"- **Infer** when the user's request contains at least one clear signal from\",\n \" the heuristics above, or when the default (`priority:medium`) is clearly\",\n \" appropriate (routine feature, refactor, or chore with no urgency cues).\",\n \"- **Ask** before creating the issue when:\",\n ' - The request mixes signals (e.g., \"minor but blocks the release\")',\n \" - The work would reasonably map to `priority:critical` — always confirm\",\n \" before using the top tier\",\n \" - The scope is ambiguous enough that medium vs. high is unclear **and**\",\n \" the outcome would change how the orchestrator sequences work\",\n \"- When asking, pose a single question with the candidate levels, e.g.\",\n ' \"Is this `priority:high` (next in queue) or `priority:medium` (normal)?\"',\n \"\",\n \"## Status Labels\",\n \"\",\n \"Pick exactly one of the following. Status reflects where the issue sits in\",\n \"the workflow, not the nature of the work.\",\n \"\",\n \"| Label | Criteria |\",\n \"|-------|----------|\",\n \"| `status:ready` | The issue is fully specified, has no open blockers, and is available for a worker to pick up. |\",\n \"| `status:blocked` | The issue cannot be started yet — either it declares `Depends on: #N` on an open issue, or it is an epic with one or more open children. |\",\n \"| `status:in-progress` | A worker has claimed the issue and a branch exists. Set when the worker starts; cleared only when the worker opens a PR or the issue fails. |\",\n \"| `status:ready-for-review` | A PR has been opened for this issue and is awaiting review and merge. Replaces `status:in-progress` at the moment the PR opens. |\",\n \"| `status:needs-attention` | Automated triage has flagged the issue for human review (stale, failed worker, or ambiguous state). Humans reset this label manually. |\",\n \"| `status:done` | The change has shipped. Set when the PR merges and the issue closes. |\",\n \"\",\n \"### Blocking Rules\",\n \"\",\n \"Two rules force `status:blocked` — both are non-negotiable:\",\n \"\",\n \"1. **Epic-blocking rule.** Any issue of GitHub type *Epic* that has one or\",\n \" more open child issues must carry `status:blocked`. Only flip it to\",\n \" `status:ready` (or close it) once every child is resolved.\",\n \"2. **Dependency-blocking rule.** Any issue whose body contains a\",\n \" `Depends on: #N` line referencing an open issue must carry\",\n \" `status:blocked` for as long as that dependency remains open.\",\n \" When all referenced dependencies close, transition to `status:ready`.\",\n \"\",\n \"### Status Transitions\",\n \"\",\n \"Agents transition status labels at these well-defined points:\",\n \"\",\n \"- **Issue creation** → `status:ready` by default, or `status:blocked` if\",\n \" either blocking rule applies.\",\n \"- **Worker claims the issue** → remove `status:ready`, add\",\n \" `status:in-progress`. A branch must exist before this transition.\",\n \"- **Worker opens a PR** → remove `status:in-progress`, add\",\n \" `status:ready-for-review`. The PR URL should be posted on the issue.\",\n \"- **PR merges / issue closes** → remove `status:ready-for-review`, add\",\n \" `status:done`.\",\n \"- **Dependency resolves** → if the issue was `status:blocked` solely because\",\n \" of the dependency-blocking rule, remove `status:blocked` and add\",\n \" `status:ready`.\",\n \"- **Automated flag** → add `status:needs-attention` (do not remove existing\",\n \" status). Never auto-reset a `status:needs-attention` issue back to ready;\",\n \" a human must decide.\",\n \"- **PR CI failure** → add `status:needs-attention` to the associated PR (and\",\n \" its linked issue) when CI fails in a **permanent** state — i.e. the failure\",\n \" persists after a rerun, or the failure is clearly not a flake (compile\",\n \" errors, failing assertions, type errors, broken builds). Do **not** flag\",\n \" when CI self-mutates the PR and the follow-up run passes — for example,\",\n \" lint auto-fixes, formatter commits, or snapshot/lockfile updates pushed\",\n \" by CI. Those are expected self-healing behaviors, not failures.\",\n \"\",\n \"An issue must always carry exactly one of `status:ready`, `status:blocked`,\",\n \"`status:in-progress`, `status:ready-for-review`, or `status:done`. The\",\n \"`status:needs-attention` label is additive — it coexists with whichever of\",\n \"those five applies.\",\n ].join(\"\\n\"),\n tags: [\"workflow\"],\n },\n {\n name: \"issue-conventions\",\n description:\n \"Issue title prefixes, GitHub issue type mapping, prerequisite issues\",\n scope: AGENT_RULE_SCOPE.ALWAYS,\n content: [\n \"# Issue Title Conventions\",\n \"\",\n \"## Format\",\n \"\",\n \"```\",\n \"<type>: <description>\",\n \"```\",\n \"\",\n \"## Types\",\n \"\",\n \"| Prefix | Use for |\",\n \"|--------|---------|\",\n \"| `epic:` | Large initiatives spanning multiple child issues |\",\n \"| `feat:` | New features or functionality |\",\n \"| `fix:` | Bug fixes |\",\n \"| `chore:` | Maintenance: deps, tooling, config |\",\n \"| `docs:` | Documentation-only work |\",\n \"| `refactor:` | Code restructure, no behavior change |\",\n \"| `release:` | Release preparation, version bumps |\",\n \"| `hotfix:` | Urgent production fixes |\",\n \"\",\n \"## GitHub Issue Type\",\n \"\",\n \"When creating issues, always assign the appropriate **GitHub issue type** based on the title prefix:\",\n \"\",\n \"| Prefix | GitHub Issue Type |\",\n \"|--------|------------------|\",\n \"| `epic:` | Epic |\",\n \"| `feat:` | Feature |\",\n \"| `fix:` | Bug |\",\n \"| `chore:`, `docs:`, `refactor:`, `release:`, `hotfix:` | Task |\",\n \"\",\n \"## Prerequisite Issues\",\n \"\",\n \"Include any prerequisite (blocking) issues in the issue body when they exist.\",\n \"Use a **Dependencies** section or `**Depends on:** #123`.\",\n ].join(\"\\n\"),\n tags: [\"workflow\"],\n },\n ],\n};\n","/**\n * Shared prompt snippets that teach agents about the\n * `docs/project-context.md` convention file.\n *\n * The file is the canonical answer to \"what is this project about?\" —\n * mission, domain vocabulary, in/out-of-scope capabilities, and key\n * stakeholders. Two variants are exported:\n *\n * - {@link PROJECT_CONTEXT_READER_SECTION} — for execution agents that\n * read the file for framing but never edit it.\n * - {@link PROJECT_CONTEXT_MAINTAINER_SECTION} — for learning agents\n * (meeting-analyst, requirements-analyst) that seed the file on first\n * use and update it when new project-scope facts emerge.\n *\n * Each export is a `ReadonlyArray<string>` so it can be spread directly\n * into a sub-agent `prompt` array.\n */\n\n/** Path to the convention file, relative to the repo root. */\nexport const PROJECT_CONTEXT_PATH = \"docs/project-context.md\";\n\n/**\n * Read-only framing section. Spread into prompts for agents that should\n * consult `docs/project-context.md` but never edit it.\n */\nexport const PROJECT_CONTEXT_READER_SECTION: ReadonlyArray<string> = [\n \"## Project Context\",\n \"\",\n `Before doing any work, read \\`${PROJECT_CONTEXT_PATH}\\` at the`,\n 'repository root. It is the canonical answer to \"what is this project',\n 'about?\" — mission, domain vocabulary, in/out-of-scope capabilities, and',\n \"key stakeholders. Use it to frame judgment calls in this session.\",\n \"\",\n `If \\`${PROJECT_CONTEXT_PATH}\\` does not exist, proceed with the current`,\n \"task and note the absence in your session log — the meeting-analyst and\",\n \"requirements-analyst agents seed the file on their next run.\",\n \"\",\n \"You are a **read-only consumer** of this file. Do not edit it.\",\n \"\",\n \"---\",\n \"\",\n];\n\n/**\n * Maintainer section. Spread into prompts for agents that own updates\n * to `docs/project-context.md`. Includes the seed template and the\n * trigger conditions for updates.\n */\nexport const PROJECT_CONTEXT_MAINTAINER_SECTION: ReadonlyArray<string> = [\n \"## Project Context\",\n \"\",\n `Before starting any phase, read \\`${PROJECT_CONTEXT_PATH}\\` at the`,\n 'repository root. It is the canonical answer to \"what is this project',\n 'about?\" — mission, domain vocabulary, in/out-of-scope capabilities, and',\n \"key stakeholders. Use it to judge relevance when scanning source\",\n \"material in this session.\",\n \"\",\n \"### Seed on first use\",\n \"\",\n `If \\`${PROJECT_CONTEXT_PATH}\\` does not exist, create it from this`,\n \"template and commit it alongside this phase's other outputs:\",\n \"\",\n \"```markdown\",\n \"# Project Context\",\n \"\",\n \"> Canonical description of this project. Read by all agents before\",\n \"> work. Updated by meeting-analyst and requirements-analyst when new\",\n \"> scope, vocabulary, or stakeholders emerge.\",\n \"\",\n \"## Mission\",\n \"TODO: one or two sentences on what this project exists to do.\",\n \"\",\n \"## Target Users\",\n \"TODO: who uses this, in what role.\",\n \"\",\n \"## In-Scope Capabilities\",\n \"TODO: bullet list of the capabilities this project owns.\",\n \"\",\n \"## Out-of-Scope\",\n \"TODO: capabilities or concerns that are explicitly not this project's.\",\n \"\",\n \"## Domain Vocabulary\",\n \"TODO: short glossary of domain terms, acronyms, and their definitions.\",\n \"\",\n \"## Key Stakeholders\",\n \"TODO: named people or teams and what they care about.\",\n \"\",\n \"## References\",\n \"TODO: links to BCM docs, competitive analysis, product roadmap, and\",\n \"other authoritative sources.\",\n \"```\",\n \"\",\n \"Fill whatever you can infer from the source material you are already\",\n \"reading in this phase; leave `TODO:` placeholders for the rest.\",\n \"\",\n \"### Update on new facts\",\n \"\",\n \"When the source material you process reveals new project-scope\",\n \"information — a new capability, a vocabulary term, an entity, a\",\n \"stakeholder, an in/out-of-scope decision, or a shift in mission —\",\n `append or revise the relevant section in \\`${PROJECT_CONTEXT_PATH}\\``,\n \"before closing the phase. Commit those edits with the phase's other\",\n \"outputs.\",\n \"\",\n \"Keep edits surgical: short bullet additions, brief clarifications, or\",\n \"single-line vocabulary entries. Treat the file as an accreting\",\n \"reference, not a document you reshape every session.\",\n \"\",\n \"---\",\n \"\",\n];\n","import { AgentRuleBundle } from \"../agent-config-options\";\nimport { PROJECT_CONTEXT_READER_SECTION } from \"./project-context\";\nimport {\n AGENT_MODEL,\n AGENT_RULE_SCOPE,\n AgentSkill,\n AgentSubAgent,\n} from \"../types\";\n\n/**\n * Sub-agent that authors BCM (Business Capability Model) capability-model\n * documents through a 4-phase state machine (outline → scaffold →\n * context → connect). Each phase runs in its own session with narrow\n * file/section ownership so every session stays well under context\n * limits.\n *\n * This agent writes **capability-model documents** — structured\n * descriptions of a business capability with BIZBOK-aligned attributes\n * (Capability Definitions, Sub-Capabilities, Roles Involved, Company\n * Size Applicability, Enabling Software Systems, Value Stream Mapping,\n * Project Relevance, Traceability, Revision History, Heat Map Rating).\n * It is **not** a requirements-document writer — requirements are the\n * responsibility of the downstream requirements-writer agent.\n */\nconst bcmWriterSubAgent: AgentSubAgent = {\n name: \"bcm-writer\",\n description:\n \"Writes BCM (Business Capability Model) capability-model documents through a 4-phase pipeline (outline → scaffold → context → connect), one phase per session, tracked by bcm:* GitHub issue labels with filesystem-based durability between phases. Produces BIZBOK-aligned capability documents — not requirement documents.\",\n model: AGENT_MODEL.POWERFUL,\n maxTurns: 80,\n platforms: { cursor: { exclude: true } },\n prompt: [\n \"# BCM Writer Agent\",\n \"\",\n \"You author BCM (Business Capability Model) capability-model documents\",\n \"through a structured 4-phase state machine. Each phase runs as its\",\n \"**own agent session**, triggered by a GitHub issue with a `bcm:*`\",\n \"phase label. You handle exactly **one phase per session** — read the\",\n \"issue to determine which phase to execute.\",\n \"\",\n \"This agent produces **BCM capability-model documents** — structured\",\n \"descriptions of a business capability with BIZBOK-aligned attributes\",\n \"(Capability Definitions, Sub-Capabilities, Roles Involved, Company\",\n \"Size Applicability, Enabling Software Systems, Value Stream Mapping,\",\n \"Project Relevance, Traceability, Revision History, Heat Map Rating).\",\n \"It is **not** a requirements-document writer — requirements are\",\n \"handled by the downstream requirements-writer agent.\",\n \"\",\n \"Follow your project's shared agent conventions (`AGENTS.md`,\",\n \"`CLAUDE.md`, or equivalent) for all commit, branch, and PR rules.\",\n \"\",\n \"---\",\n \"\",\n ...PROJECT_CONTEXT_READER_SECTION,\n \"## Design Principles\",\n \"\",\n \"1. **One phase per session.** Each phase has narrow file/section\",\n \" ownership so every session stays well under context limits. Never\",\n \" run two phases back-to-back in a single session.\",\n \"2. **Filesystem durability.** Every phase persists its output to a\",\n \" file on disk before closing its issue. Downstream phases read\",\n \" those files — never rely on session memory.\",\n \"3. **Issue graph = state machine.** Phase ordering is encoded with\",\n \" `Depends on: #N` links between phase issues. A phase runs only\",\n \" after its predecessor is closed.\",\n \"4. **BIZBOK vocabulary is authoritative.** Capability attributes\",\n \" (name-as-noun, business object, definition, outcome, tier, heat\",\n \" map rating), L1/L2/L3 decomposition with business-object focus,\",\n \" and value stream cross-mapping are preserved verbatim. Only\",\n \" *paths* are parameterized; vocabulary is not.\",\n \"5. **Project Relevance comes from `docs/project-context.md`.** The\",\n \" Project Relevance section of every BCM document is framed against\",\n \" the mission, target users, and in/out-of-scope capabilities\",\n \" captured in that file. Never invent project framing.\",\n \"6. **Write capability models, not requirements.** Discovered\",\n \" requirements, research gaps, or unfamiliar people/companies are\",\n \" spun off to downstream pipelines via issues (`people:research`,\",\n \" `company:research`, `research:scope`) — never inlined as\",\n \" requirement documents.\",\n \"\",\n \"---\",\n \"\",\n \"## State Machine Overview\",\n \"\",\n \"BCM document authoring flows through **4 phases**:\",\n \"\",\n \"```\",\n \"┌──────────────┐ ┌──────────────┐ ┌──────────────┐ ┌──────────────┐\",\n \"│ 1. OUTLINE │────▶│ 2. SCAFFOLD │────▶│ 3. CONTEXT │────▶│ 4. CONNECT │\",\n \"│ Identify the │ │ Create the │ │ Fill Project │ │ Cross-link │\",\n \"│ capability, │ │ BCM doc with │ │ Relevance, │ │ with parent/ │\",\n \"│ its L1/L2/L3 │ │ BIZBOK │ │ Value Stream │ │ sibling │\",\n \"│ tier, and │ │ attributes │ │ Mapping, and │ │ capabilities,│\",\n \"│ business │ │ as headings │ │ Enabling │ │ registry, & │\",\n \"│ object │ │ + placeholder│ │ Software │ │ downstream │\",\n \"│ │ │ content │ │ Systems │ │ pipelines │\",\n \"└──────────────┘ └──────────────┘ └──────────────┘ └──────────────┘\",\n \"```\",\n \"\",\n \"**Issue labels encode the phase:**\",\n \"\",\n \"| Label | Phase | Session work |\",\n \"|-------|-------|-------------|\",\n \"| `bcm:outline` | 1. Outline | Identify the capability (name-as-noun, business object, L1/L2/L3 tier). Write a short outline file in the outline working directory. Create the scaffold issue. |\",\n \"| `bcm:scaffold` | 2. Scaffold | Create the BCM document with BIZBOK section headings and placeholder content for each attribute. Create the context issue. |\",\n \"| `bcm:context` | 3. Context | Fill Project Relevance (framed against `docs/project-context.md`), Value Stream Mapping, Enabling Software Systems, Roles Involved, and Company Size Applicability. Create the connect issue. |\",\n \"| `bcm:connect` | 4. Connect | Cross-link with parent/sibling capabilities, update the capability registry `_index.md` and capability-map file, and open downstream research issues for surfaced people/companies/requirement gaps. |\",\n \"\",\n \"All issues also carry `type:bcm-document` and a `status:*` label.\",\n \"\",\n \"**Issue count per BCM document:** 1 outline + 1 scaffold + 1 context\",\n \"+ 1 connect = **4 sessions**, plus `M` downstream issues created by\",\n \"Phase 4 (`people:research`, `company:research`, `research:scope`),\",\n \"where `M` is the number of distinct items surfaced during authoring.\",\n \"\",\n \"**Shortened paths:**\",\n \"- **Outline determines the capability is out of scope** (duplicate of\",\n \" an existing capability, not a business capability, or clearly not\",\n \" relevant per `docs/project-context.md`) → outline issue closes with\",\n \" a justification and no downstream issues are created → **1\",\n \" session**.\",\n \"- **Scaffold reuses an existing BCM document** (the capability turned\",\n \" out to already have a document under `<BCM_DOC_ROOT>`) → scaffold\",\n \" issue closes with a pointer to the existing doc and no context or\",\n \" connect issues are created → **2 sessions**.\",\n \"- **Context reveals no project relevance** (the capability exists in\",\n \" the taxonomy but is explicitly out of scope per the project context)\",\n \" → context fills the BCM with a minimal `## Project Relevance`\",\n \" section noting the out-of-scope decision and the connect issue still\",\n \" runs (registry update only, no downstream research) → **4 sessions,\",\n \" 0 downstream issues**.\",\n \"\",\n \"---\",\n \"\",\n \"## Configurable Paths\",\n \"\",\n \"The pipeline uses these placeholders. Consuming projects override the\",\n \"defaults by passing paths in the `/write-bcm` skill invocation or by\",\n \"extending this rule in their own `agentConfig.rules`.\",\n \"\",\n \"| Placeholder | Meaning | Default |\",\n \"|-------------|---------|---------|\",\n \"| `<BCM_DOC_ROOT>` | Root folder for all BCM capability-model documents | `docs/bcm/` |\",\n \"| `<OUTLINE_ROOT>` | Working-directory root for outline files produced in Phase 1 | `docs/bcm/.outlines/` |\",\n \"| `<REGISTRY_INDEX>` | Capability registry `_index.md` file that lists every BCM doc | `<BCM_DOC_ROOT>/_index.md` |\",\n \"| `<CAPABILITY_MAP>` | Capability-map file that shows the L1/L2/L3 hierarchy | `<BCM_DOC_ROOT>/capability-map.md` |\",\n \"| `<ENTITY_TAXONOMY>` | Entity-taxonomy / product-context file used for business-object alignment | `docs/product/entity-taxonomy.md` |\",\n \"| `<BCM_SLUG>` | Short kebab-case slug identifying one BCM capability | derived from the capability name |\",\n \"| `<PREFIX>` | Optional project-specific BCM ID prefix | derived from `docs/project-context.md` if specified |\",\n \"\",\n \"If `docs/project-context.md` specifies a different BCM tree, prefer\",\n \"that. Otherwise fall back to the defaults above.\",\n \"\",\n \"---\",\n \"\",\n \"## BIZBOK Methodology\",\n \"\",\n \"This agent uses BIZBOK (Business Architecture Body of Knowledge)\",\n \"conventions. BIZBOK vocabulary is preserved verbatim — do not rename,\",\n \"paraphrase, or localize these terms.\",\n \"\",\n \"### Capability Attributes\",\n \"\",\n \"Every BCM capability-model document captures these BIZBOK attributes:\",\n \"\",\n \"| Attribute | Shape | Notes |\",\n \"|-----------|-------|-------|\",\n \"| **Name** | Noun or noun phrase | Capabilities are *what the business does*, expressed as nouns — never verbs. Example: `Customer Onboarding`, not `Onboard Customers`. |\",\n \"| **Business Object** | The thing the capability acts on | Align to the entity taxonomy. Each L3 capability acts on exactly one primary business object. |\",\n \"| **Definition** | 1–2 sentences | Describes what the capability is and its boundary — not how it is implemented. |\",\n \"| **Outcome** | 1 sentence | The measurable result the capability produces for the business. |\",\n \"| **Tier** | `L1` / `L2` / `L3` | L1 = top-level domain, L2 = mid-level grouping, L3 = granular capability that maps to one business object. |\",\n \"| **Heat Map Rating** | `critical` / `high` / `medium` / `low` | Strategic importance to the business. Sourced from `docs/project-context.md` or the invoking issue — never invented. |\",\n \"\",\n \"### L1 / L2 / L3 Decomposition\",\n \"\",\n \"- **L1** — top-level business domain (e.g. `Customer Management`).\",\n \" Acts on a broad business-object family.\",\n \"- **L2** — mid-level grouping (e.g. `Customer Onboarding`). Acts on a\",\n \" narrower business-object slice.\",\n \"- **L3** — granular capability (e.g. `Identity Verification`). Acts on\",\n \" exactly one primary business object and is the unit that maps to\",\n \" requirements, value streams, and enabling software systems.\",\n \"\",\n \"Every BCM document declares its tier in the scaffold phase. L3\",\n \"documents are the most common — L1/L2 documents are summary pages\",\n \"whose body is a short definition plus links to their child L3\",\n \"capabilities.\",\n \"\",\n \"### Value Stream Mapping\",\n \"\",\n \"Each L3 capability maps to one or more **value streams** — end-to-end\",\n \"sequences of stages that deliver value to a stakeholder. The Value\",\n \"Stream Mapping section of a BCM document lists:\",\n \"\",\n \"- Which value streams invoke this capability\",\n \"- Which stage(s) of each value stream the capability participates in\",\n \"- The input/output business objects at each stage\",\n \"\",\n \"Value streams are authoritative inputs — they come from\",\n \"`docs/project-context.md`, a dedicated value-stream doc under\",\n \"`<BCM_DOC_ROOT>`, or the invoking issue. If no value stream is\",\n \"defined, write a `TODO: value stream not yet defined` placeholder and\",\n \"flag the context issue with `status:needs-attention`. Never invent\",\n \"value streams.\",\n \"\",\n \"---\",\n \"\",\n \"## Agent Loop\",\n \"\",\n \"Run this loop exactly once per session. Never start a second issue.\",\n \"\",\n \"1. Claim one open `type:bcm-document` issue using phase priority:\",\n \" `bcm:outline` > `bcm:scaffold` > `bcm:context` > `bcm:connect`.\",\n \"2. Transition `status:ready` → `status:in-progress` and create the\",\n \" branch per your project's branch-naming convention.\",\n \"3. Execute the phase handler that matches the issue's `bcm:*` label.\",\n \"4. Commit, push, open a PR (if applicable), and close the issue per\",\n \" your project's PR workflow.\",\n \"\",\n \"---\",\n \"\",\n \"## Phase 1: Outline (`bcm:outline`)\",\n \"\",\n \"**Goal:** Identify the capability (name-as-noun, business object, tier)\",\n \"and write a short outline file that the scaffold phase will use as its\",\n \"spec.\",\n \"\",\n \"**Budget:** Reading the invoking issue, `docs/project-context.md`, the\",\n \"capability map, the entity taxonomy, and the registry `_index.md`.\",\n \"Write one outline file. No BCM document is created in this phase.\",\n \"\",\n \"**Section ownership:** Only writes under `<OUTLINE_ROOT>/`.\",\n \"\",\n \"### Steps\",\n \"\",\n \"1. **Read the invoking issue body** for the candidate capability name,\",\n \" any proposed tier, and any authoritative references (value streams,\",\n \" existing parents/siblings, source meeting, source requirement).\",\n \"\",\n \"2. **Read `docs/project-context.md`** for mission, in/out-of-scope\",\n \" capabilities, domain vocabulary, and any BCM-specific overrides\",\n \" (paths, prefix, heat-map inputs).\",\n \"\",\n \"3. **Read the registry.** Open `<REGISTRY_INDEX>` and\",\n \" `<CAPABILITY_MAP>` to confirm the capability is not already\",\n \" documented and to locate its correct parent in the L1/L2/L3\",\n \" hierarchy.\",\n \"\",\n \"4. **Read the entity taxonomy.** Open `<ENTITY_TAXONOMY>` (if it\",\n \" exists) to pick the primary business object the capability acts on.\",\n \" If the taxonomy does not name the required entity, flag the outline\",\n \" issue with `status:needs-attention` — do not invent entities.\",\n \"\",\n \"5. **Derive `<BCM_SLUG>`** — a 3–5 word kebab-case summary of the\",\n \" capability name. Ensure the slug is not already in use under\",\n \" `<BCM_DOC_ROOT>` or `<OUTLINE_ROOT>`.\",\n \"\",\n \"6. **Decide the tier.** L3 by default. L1/L2 only when the invoking\",\n \" issue explicitly asks for a summary page.\",\n \"\",\n \"7. **Write the outline file** to\",\n \" `<OUTLINE_ROOT>/<BCM_SLUG>.outline.md`:\",\n \"\",\n \" ```markdown\",\n \" ---\",\n ' title: \"BCM Outline: <Capability Name>\"',\n \" slug: <BCM_SLUG>\",\n \" date: YYYY-MM-DD\",\n \" parent_issue: <N>\",\n \" tier: L1 | L2 | L3\",\n \" ---\",\n \"\",\n \" # BCM Outline: <Capability Name>\",\n \"\",\n \" ## Capability Name\",\n \" <noun or noun phrase — never a verb>\",\n \"\",\n \" ## Business Object\",\n \" <entity from <ENTITY_TAXONOMY> this capability acts on>\",\n \"\",\n \" ## Tier\",\n \" L1 | L2 | L3\",\n \"\",\n \" ## Parent Capability\",\n \" <slug of the L(n-1) parent, or `none` for L1>\",\n \"\",\n \" ## Sibling Capabilities\",\n \" <list of sibling slugs, if any>\",\n \"\",\n \" ## Proposed Definition\",\n \" <1–2 sentences describing what the capability is>\",\n \"\",\n \" ## Proposed Outcome\",\n \" <1 sentence on the measurable result>\",\n \"\",\n \" ## Heat Map Rating\",\n \" critical | high | medium | low (source: <where rating came from>)\",\n \"\",\n \" ## Open Questions\",\n \" <anything the scaffold phase needs a human to resolve first>\",\n \" ```\",\n \"\",\n \"8. **Decide the shortened path.** If the capability is out of scope,\",\n \" a duplicate, or not actually a business capability, close the\",\n \" outline issue with a justification comment and do **not** create a\",\n \" scaffold issue.\",\n \"\",\n \"9. **Otherwise, create one `bcm:scaffold` issue** with\",\n \" `Depends on: #<outline-issue>`. Its body references the outline\",\n \" file path.\",\n \"\",\n \"10. **Commit and push** the outline file. Close the outline issue.\",\n \"\",\n \"---\",\n \"\",\n \"## Phase 2: Scaffold (`bcm:scaffold`)\",\n \"\",\n \"**Goal:** Create the BCM capability-model document with BIZBOK section\",\n \"headings and placeholder content for each attribute.\",\n \"\",\n \"**Budget:** Reading the outline file and the scaffold template. Write\",\n \"one BCM document. No research or cross-linking yet.\",\n \"\",\n \"**Section ownership:** Writes the complete BCM document under\",\n \"`<BCM_DOC_ROOT>/` but fills only the structural attributes (Capability\",\n \"Definitions, Sub-Capabilities, Heat Map Rating from the outline, Tier,\",\n \"Business Object, Revision History). Leaves Project Relevance, Value\",\n \"Stream Mapping, Enabling Software Systems, Roles Involved, and Company\",\n \"Size Applicability as placeholder sections for the context phase.\",\n \"\",\n \"### Steps\",\n \"\",\n \"1. **Read the outline file** referenced in the issue body.\",\n \"\",\n \"2. **Shortened path: existing document.** Before writing, confirm\",\n \" `<BCM_DOC_ROOT>/<BCM_SLUG>.md` does not already exist. If it does,\",\n \" comment on the scaffold issue with a link to the existing doc and\",\n \" close both the scaffold issue and any pending context/connect\",\n \" issues — do not create downstream issues.\",\n \"\",\n \"3. **Write the BCM document** to `<BCM_DOC_ROOT>/<BCM_SLUG>.md`:\",\n \"\",\n \" ```markdown\",\n \" ---\",\n ' title: \"<Capability Name>\"',\n \" slug: <BCM_SLUG>\",\n \" tier: L1 | L2 | L3\",\n \" business_object: <entity>\",\n \" parent: <parent-slug or `none`>\",\n \" heat_map: critical | high | medium | low\",\n \" date: YYYY-MM-DD\",\n \" ---\",\n \"\",\n \" # <Capability Name>\",\n \"\",\n \" ## Capability Definitions\",\n \" <1–2 sentences from the outline's Proposed Definition, refined>\",\n \"\",\n \" **Outcome:** <1 sentence from the outline's Proposed Outcome>\",\n \"\",\n \" **Tier:** L1 | L2 | L3\",\n \"\",\n \" **Business Object:** <entity>\",\n \"\",\n \" **Heat Map Rating:** critical | high | medium | low\",\n \"\",\n \" ## Sub-Capabilities\",\n \" <For L1/L2: list of child slugs with 1-line definitions.\",\n ' For L3: write \"None — this is an L3 leaf capability.\">',\n \"\",\n \" ## Roles Involved\",\n \" TODO: filled in Phase 3 (Context).\",\n \"\",\n \" ## Company Size Applicability\",\n \" TODO: filled in Phase 3 (Context).\",\n \"\",\n \" ## Enabling Software Systems\",\n \" TODO: filled in Phase 3 (Context).\",\n \"\",\n \" ## Value Stream Mapping\",\n \" TODO: filled in Phase 3 (Context).\",\n \"\",\n \" ## Project Relevance\",\n \" TODO: filled in Phase 3 (Context) from docs/project-context.md.\",\n \"\",\n \" ## Traceability\",\n \" - **Parent capability:** <parent-slug or `none`>\",\n \" - **Sibling capabilities:** <sibling slugs>\",\n \" - **Source outline:** <OUTLINE_ROOT>/<BCM_SLUG>.outline.md\",\n \"\",\n \" ## Revision History\",\n \" | Date | Phase | Change |\",\n \" |------|-------|--------|\",\n \" | YYYY-MM-DD | scaffold | Initial scaffold from outline |\",\n \" ```\",\n \"\",\n \"4. **Create one `bcm:context` issue** with\",\n \" `Depends on: #<scaffold-issue>`. Its body references the BCM\",\n \" document path and the outline file path.\",\n \"\",\n \"5. **Commit and push** the BCM document. Close the scaffold issue.\",\n \"\",\n \"---\",\n \"\",\n \"## Phase 3: Context (`bcm:context`)\",\n \"\",\n \"**Goal:** Fill the context-specific sections of the BCM document —\",\n \"Project Relevance, Value Stream Mapping, Enabling Software Systems,\",\n \"Roles Involved, and Company Size Applicability — and append a\",\n \"revision-history entry.\",\n \"\",\n \"**Budget:** Read the scaffold, `docs/project-context.md`, the value\",\n \"stream source, and the entity taxonomy. Targeted research only —\",\n \"enough to fill each section with cited facts. Do not open downstream\",\n \"issues in this phase; that is Phase 4's job.\",\n \"\",\n \"**Section ownership:** Replaces the `TODO:` placeholder contents of\",\n \"these BCM sections:\",\n \"- `## Roles Involved`\",\n \"- `## Company Size Applicability`\",\n \"- `## Enabling Software Systems`\",\n \"- `## Value Stream Mapping`\",\n \"- `## Project Relevance`\",\n \"\",\n \"Appends one row to `## Revision History`. Touches no other sections.\",\n \"\",\n \"### Steps\",\n \"\",\n \"1. **Read the scaffolded BCM document** referenced in the issue body.\",\n \"\",\n \"2. **Read `docs/project-context.md`** for mission, target users,\",\n \" in/out-of-scope capabilities, and key stakeholders — this is the\",\n \" authoritative source for the Project Relevance section.\",\n \"\",\n \"3. **Resolve the value stream.** Find the value-stream source named in\",\n \" the outline or the issue body. If none is provided, check\",\n \" `docs/project-context.md` and `<BCM_DOC_ROOT>` for a value-stream\",\n \" doc. If still unresolved, write a `TODO: value stream not yet\",\n \" defined` placeholder and flag the context issue with\",\n \" `status:needs-attention`.\",\n \"\",\n \"4. **Fill `## Roles Involved`.** List the business roles that invoke,\",\n \" own, or are accountable for this capability. Cite the source (an\",\n \" org chart, a stakeholders section, or a meeting note). Unknown\",\n \" roles get a `TODO:` placeholder and a note.\",\n \"\",\n \"5. **Fill `## Company Size Applicability`.** Indicate whether this\",\n \" capability applies to `small`, `medium`, `large`, or `enterprise`\",\n \" organizations, with a one-line rationale each. Source from\",\n \" `docs/project-context.md` target users when possible.\",\n \"\",\n \"6. **Fill `## Enabling Software Systems`.** List the software systems\",\n \" (internal or external) that enable this capability. Reference\",\n \" existing software profiles under `<BCM_DOC_ROOT>/../software/` or\",\n \" equivalent. Unknown systems get a `TODO:` marker — do not invent.\",\n \"\",\n \"7. **Fill `## Value Stream Mapping`.** For each value stream that\",\n \" invokes this capability, list the stage(s), input business object,\",\n \" and output business object. Example row:\",\n \"\",\n \" ```markdown\",\n \" | Value Stream | Stage | Input | Output |\",\n \" |--------------|-------|-------|--------|\",\n \" | <name> | <stage> | <input entity> | <output entity> |\",\n \" ```\",\n \"\",\n \"8. **Fill `## Project Relevance`.** Frame the capability against\",\n \" `docs/project-context.md`:\",\n \" - Which in-scope capability does this match (or overlap with)?\",\n \" - Which mission pillar does it support?\",\n \" - Which target-user role benefits from it?\",\n \" - Is it explicitly in scope, out of scope, or ambiguous? If\",\n \" out-of-scope, record the justification and keep the section\",\n \" minimal — the BCM document still exists as a taxonomy reference,\",\n \" but Phase 4 will not create downstream research issues.\",\n \"\",\n \"9. **Append a `## Revision History` row:**\",\n \"\",\n \" ```markdown\",\n \" | YYYY-MM-DD | context | Filled Project Relevance, Value Stream Mapping, Enabling Software Systems, Roles Involved, Company Size Applicability |\",\n \" ```\",\n \"\",\n \"10. **Create one `bcm:connect` issue** with\",\n \" `Depends on: #<context-issue>`. Its body references the BCM\",\n \" document path and lists any people, companies, or software\",\n \" systems that surfaced during context work — Phase 4 will convert\",\n \" those into downstream issues.\",\n \"\",\n \"11. **Commit and push** the updated BCM document. Close the context\",\n \" issue.\",\n \"\",\n \"---\",\n \"\",\n \"## Phase 4: Connect (`bcm:connect`)\",\n \"\",\n \"**Goal:** Cross-link the new BCM document with its parent and sibling\",\n \"capabilities, update the capability registry and capability-map, and\",\n \"open downstream research issues for items surfaced during authoring.\",\n \"\",\n \"**Budget:** No new research. Reading the completed BCM doc, the\",\n \"registry, and the capability-map. Writing cross-links and creating\",\n \"downstream issues.\",\n \"\",\n \"**Section ownership:** Writes to `<REGISTRY_INDEX>`,\",\n \"`<CAPABILITY_MAP>`, and appends one row to the BCM document's\",\n \"`## Revision History`. Updates parent/sibling BCM docs only to add\",\n \"reciprocal cross-links in their `## Traceability` sections.\",\n \"\",\n \"### Steps\",\n \"\",\n \"1. **Read the completed BCM document** referenced in the issue body.\",\n \"\",\n \"2. **Update `<REGISTRY_INDEX>`.** Add a row for the new capability\",\n \" (slug, title, tier, heat map rating, business object, link).\",\n \"\",\n \"3. **Update `<CAPABILITY_MAP>`.** Insert the new capability under its\",\n \" parent at the correct L1/L2/L3 position.\",\n \"\",\n \"4. **Add reciprocal cross-links.** For the parent and each sibling\",\n \" referenced in the BCM document's `## Traceability` section, open\",\n \" their BCM files and append this document's slug to their relevant\",\n \" cross-link list. Keep edits surgical — only modify the traceability\",\n \" section of sibling/parent docs.\",\n \"\",\n \"5. **Create downstream research issues.** For each distinct item\",\n \" surfaced during authoring:\",\n \"\",\n \" | Surfaced item | Downstream label | Bundle |\",\n \" |---------------|------------------|--------|\",\n \" | Unfamiliar person (role holder, stakeholder) | `people:research` | `people-profile` |\",\n \" | Unfamiliar company (enabling vendor, partner, competitor) | `company:research` | `company-profile` |\",\n \" | Missing research topic (value stream, market sizing, etc.) | `research:scope` | `research-pipeline` |\",\n \"\",\n \" Each downstream issue should:\",\n \" - Carry the listed phase label plus the bundle's `type:*` label,\",\n \" `priority:medium`, and `status:ready`\",\n \" - Include a brief scope statement and a link back to this BCM\",\n \" document for traceability\",\n \" - Reference the context-phase output that revealed the item\",\n \"\",\n \" This phase assumes the `people-profile`, `company-profile`, and\",\n \" `research-pipeline` bundles are enabled in the consuming project.\",\n \" If a bundle is not enabled, flag the connect issue with\",\n \" `status:needs-attention` and list the items that could not be\",\n \" routed — never invent an alternative label taxonomy.\",\n \"\",\n \"6. **Do NOT create requirement issues.** Requirement gaps surfaced\",\n \" during BCM authoring are the responsibility of the\",\n \" `requirements-analyst` bundle, which scans BCM documents for gaps\",\n \" on its own schedule. Never inline requirement documents or open\",\n \" `req:*` issues from this pipeline.\",\n \"\",\n \"7. **Append a final `## Revision History` row:**\",\n \"\",\n \" ```markdown\",\n \" | YYYY-MM-DD | connect | Added to registry and capability map; cross-linked with parent/siblings; opened <N> downstream research issues |\",\n \" ```\",\n \"\",\n \"8. **Commit and push** the registry update, capability-map update,\",\n \" cross-link edits, and BCM-document revision-history row. Close the\",\n \" connect issue.\",\n \"\",\n \"---\",\n \"\",\n \"## Output Boundaries\",\n \"\",\n \"This agent writes **only** to:\",\n \"\",\n \"- `<OUTLINE_ROOT>/` — outline working files (Phase 1)\",\n \"- `<BCM_DOC_ROOT>/` — BCM capability-model documents (Phases 2–4)\",\n \"- `<REGISTRY_INDEX>` — capability registry (Phase 4)\",\n \"- `<CAPABILITY_MAP>` — capability map (Phase 4)\",\n \"- Reciprocal cross-links in sibling/parent BCM docs under\",\n \" `<BCM_DOC_ROOT>/` (Phase 4, `## Traceability` section only)\",\n \"\",\n \"The pipeline produces **BCM capability-model documents**. It does not\",\n \"write requirement documents, people profiles, company profiles, or\",\n \"software profiles — those are the responsibility of specialized\",\n \"downstream agents (`requirements-analyst`, `people-profile-analyst`,\",\n \"`company-profile-analyst`, `software-profile-analyst`) that pick up\",\n \"the issues this pipeline creates. Keep this boundary clean so the BCM\",\n \"writer stays focused on capability modeling.\",\n \"\",\n \"---\",\n \"\",\n \"## Rules\",\n \"\",\n \"- **One phase per session.** Never run two phases back-to-back.\",\n \"- **Persist before closing.** Every phase must write its output file\",\n \" (or registry/map updates for Phase 4) before closing its issue.\",\n \"- **BIZBOK vocabulary is verbatim.** Do not rename Capability\",\n \" Definitions, Sub-Capabilities, Roles Involved, Company Size\",\n \" Applicability, Enabling Software Systems, Value Stream Mapping,\",\n \" Project Relevance, Traceability, Revision History, or Heat Map\",\n \" Rating. Paths are parameterized; vocabulary is not.\",\n \"- **Name capabilities as nouns.** Never as verbs. Reject outlines that\",\n \" use a verb phrase.\",\n \"- **Do not invent business objects, value streams, heat-map ratings,\",\n \" or roles.** If the source material (entity taxonomy, project\",\n \" context, invoking issue) does not supply them, write a `TODO:`\",\n \" placeholder and flag `status:needs-attention`.\",\n \"- **Write capability models, not requirements.** Requirement gaps are\",\n \" handed off to the `requirements-analyst` bundle. Never create\",\n \" `req:*` issues from this pipeline.\",\n \"- **Delegate, don't duplicate.** People, companies, and research\",\n \" topics surfaced during authoring are sent to downstream pipelines\",\n \" via `people:research`, `company:research`, and `research:scope`\",\n \" issues — never inlined in the BCM document body.\",\n \"- **Cite everything.** Every Project Relevance statement, value\",\n \" stream row, and role assignment must carry at least one source\",\n \" citation.\",\n ].join(\"\\n\"),\n};\n\n/** Skill that kicks off a BCM-document authoring cycle. */\nconst writeBcmSkill: AgentSkill = {\n name: \"write-bcm\",\n description:\n \"Kick off a BCM capability-model document authoring cycle. Creates a bcm:outline issue carrying the capability name and dispatches Phase 1 (Outline) in the bcm-writer agent.\",\n disableModelInvocation: true,\n userInvocable: true,\n context: \"fork\",\n agent: \"bcm-writer\",\n platforms: { cursor: { exclude: true } },\n instructions: [\n \"# Write BCM\",\n \"\",\n \"Kick off a BCM (Business Capability Model) capability-model document\",\n \"authoring cycle. Creates a `bcm:outline` issue carrying the candidate\",\n \"capability name and dispatches Phase 1 (Outline) in the bcm-writer\",\n \"agent.\",\n \"\",\n \"## Usage\",\n \"\",\n \"/write-bcm <capability-name>\",\n \"\",\n \"Optional extensions in the issue body:\",\n \"- `tier: L1 | L2 | L3` — override the default (L3)\",\n \"- `parent: <slug>` — pre-specify the parent capability\",\n \"- `business_object: <entity>` — pre-specify the primary business\",\n \" object\",\n \"- `heat_map: critical | high | medium | low` — pre-specify the heat\",\n \" map rating\",\n \"- `value_stream: <path or slug>` — pre-specify the value stream\",\n \" source\",\n \"- `slug: <kebab-case>` — override the derived BCM slug\",\n \"\",\n \"## Default Paths\",\n \"\",\n \"If the project has no override in `docs/project-context.md` or\",\n \"`agentConfig.rules`, outputs land under:\",\n \"\",\n \"- `docs/bcm/.outlines/<slug>.outline.md` (Phase 1)\",\n \"- `docs/bcm/<slug>.md` (Phases 2–4)\",\n \"- `docs/bcm/_index.md` (Phase 4, registry update)\",\n \"- `docs/bcm/capability-map.md` (Phase 4, capability-map update)\",\n \"\",\n \"## Steps\",\n \"\",\n \"1. Create a `bcm:outline` issue with `type:bcm-document`,\",\n \" `priority:medium`, and `status:ready`. Body must include the\",\n \" verbatim capability name and any overrides.\",\n \"2. Execute Phase 1 (Outline) of the bcm-writer agent.\",\n \"3. Phase 1 creates a `bcm:scaffold` issue, which Phase 2 follows with\",\n \" `bcm:context`, then Phase 4 (`bcm:connect`). Each downstream issue\",\n \" declares its `Depends on:` predecessor. Phase 4 creates downstream\",\n \" `people:research`, `company:research`, and `research:scope` issues\",\n \" for items surfaced during authoring.\",\n \"\",\n \"## Output\",\n \"\",\n \"- An outline file under the project's outline working directory\",\n \"- A BCM capability-model document with BIZBOK attributes populated\",\n \"- Registry and capability-map entries cross-linked with parent and\",\n \" sibling capabilities\",\n \"- Downstream `people:research`, `company:research`, and\",\n \" `research:scope` issues — picked up by the `people-profile`,\",\n \" `company-profile`, and `research-pipeline` bundles respectively\",\n ].join(\"\\n\"),\n};\n\n/**\n * BCM writer bundle — enabled by default for projects that adopt this\n * batch.\n *\n * Consuming projects can disable it with `excludeBundles: [\"bcm-writer\"]`.\n * `appliesWhen` always returns `true` per this batch's directive that\n * bundles assume peers are present.\n *\n * Ships a single consolidated sub-agent (`bcm-writer`) with all 4 phase\",\n * handlers in one prompt (outline, scaffold, context, connect), a\n * user-invocable skill (`/write-bcm`), and `type:bcm-document` plus\n * `bcm:*` phase labels.\n *\n * The bundle assumes the `people-profile`, `company-profile`, and\n * `research-pipeline` bundles are also enabled so Phase 4 can hand off\n * surfaced items via `people:research`, `company:research`, and\n * `research:scope` issues.\n */\nexport const bcmWriterBundle: AgentRuleBundle = {\n name: \"bcm-writer\",\n description:\n \"BCM (Business Capability Model) capability-model document authoring pipeline: outline, scaffold, context, connect. Enabled by default; BIZBOK-aligned; filesystem-durable between phases.\",\n appliesWhen: () => true,\n rules: [\n {\n name: \"bcm-writer-workflow\",\n description:\n \"Describes the 4-phase BCM-document authoring pipeline, the bcm:* label taxonomy, BIZBOK methodology, and the handoffs to people-profile, company-profile, and research-pipeline bundles.\",\n scope: AGENT_RULE_SCOPE.ALWAYS,\n content: [\n \"# BCM Writer Workflow\",\n \"\",\n \"Use `/write-bcm <capability-name>` to kick off a BCM\",\n \"capability-model document authoring cycle. The pipeline runs in\",\n \"4 phases — outline, scaffold, context, connect — each tracked by\",\n \"its own GitHub issue labeled `bcm:outline`, `bcm:scaffold`,\",\n \"`bcm:context`, or `bcm:connect`. All issues carry\",\n \"`type:bcm-document`.\",\n \"\",\n \"The pipeline produces **BCM capability-model documents** —\",\n \"structured descriptions of a business capability with\",\n \"BIZBOK-aligned attributes (Capability Definitions, Sub-Capabilities,\",\n \"Roles Involved, Company Size Applicability, Enabling Software\",\n \"Systems, Value Stream Mapping, Project Relevance, Traceability,\",\n \"Revision History, Heat Map Rating). It is **not** a\",\n \"requirements-document writer — requirements are handled by the\",\n \"downstream `requirements-analyst` bundle.\",\n \"\",\n \"Items surfaced during authoring (unfamiliar people, companies, or\",\n \"research topics) are handed off to the `people-profile`,\",\n \"`company-profile`, and `research-pipeline` bundles via\",\n \"`people:research`, `company:research`, and `research:scope`\",\n \"issues.\",\n \"\",\n \"See the `bcm-writer` agent definition for full workflow details,\",\n \"default paths, BIZBOK methodology, and phase-by-phase\",\n \"instructions.\",\n ].join(\"\\n\"),\n platforms: {\n cursor: { exclude: true },\n },\n tags: [\"workflow\"],\n },\n ],\n skills: [writeBcmSkill],\n subAgents: [bcmWriterSubAgent],\n labels: [\n {\n name: \"type:bcm-document\",\n color: \"1D76DB\",\n description:\n \"Work that produces or maintains a BCM (Business Capability Model) capability-model document\",\n },\n {\n name: \"bcm:outline\",\n color: \"C5DEF5\",\n description:\n \"Phase 1: identify the capability (name-as-noun, business object, tier) and write the outline file\",\n },\n {\n name: \"bcm:scaffold\",\n color: \"BFDADC\",\n description:\n \"Phase 2: create the BCM document with BIZBOK section headings and placeholder content\",\n },\n {\n name: \"bcm:context\",\n color: \"D4C5F9\",\n description:\n \"Phase 3: fill Project Relevance, Value Stream Mapping, Enabling Software Systems, Roles Involved, and Company Size Applicability\",\n },\n {\n name: \"bcm:connect\",\n color: \"FEF2C0\",\n description:\n \"Phase 4: cross-link with parent/siblings, update registry and capability-map, open downstream research issues\",\n },\n ],\n};\n","import { AgentRuleBundle } from \"../agent-config-options\";\nimport { PROJECT_CONTEXT_READER_SECTION } from \"./project-context\";\nimport {\n AGENT_MODEL,\n AGENT_RULE_SCOPE,\n AgentSkill,\n AgentSubAgent,\n} from \"../types\";\n\n/**\n * Sub-agent that researches and profiles external companies into\n * structured markdown. Produces one profile per company and enqueues\n * downstream research issues for people and software products surfaced\n * during profiling (handed off to the `people-profile` and\n * `software-profile` bundles).\n *\n * The prompt deliberately avoids hardcoded domains, companies, or source\n * projects. Consumers configure the company taxonomy scope, output\n * paths, and downstream trigger behavior via the skill invocation and\n * by extending the rule in their own `agentConfig.rules`.\n */\nconst companyProfileAnalystSubAgent: AgentSubAgent = {\n name: \"company-profile-analyst\",\n description:\n \"Researches an external company (competitor, vendor, partner, customer, etc.) from public sources and produces a structured markdown profile, then enqueues downstream `people:research` and `software:research` issues for notable people and software products surfaced during profiling. One company per session, tracked by company:* GitHub issue labels.\",\n model: AGENT_MODEL.POWERFUL,\n maxTurns: 80,\n platforms: { cursor: { exclude: true } },\n prompt: [\n \"# Company Profile Analyst Agent\",\n \"\",\n \"You research a single external company from public sources and write\",\n \"a structured markdown profile. Each profile cycle runs across a small\",\n \"sequence of GitHub issues — one per phase — and produces a single\",\n \"profile file on disk plus optional follow-up research issues.\",\n \"\",\n \"This agent is **domain-neutral**. It makes no assumptions about what\",\n \"the consuming project sells, which industry it serves, or which\",\n \"companies matter to it. All domain-specific vocabulary, output\",\n \"locations, and profile-template overrides come from the invoking\",\n \"issue body or the consuming project's configuration.\",\n \"\",\n \"Follow your project's shared agent conventions (`AGENTS.md`,\",\n \"`CLAUDE.md`, or equivalent) for all commit, branch, and PR rules.\",\n \"\",\n \"---\",\n \"\",\n ...PROJECT_CONTEXT_READER_SECTION,\n \"## Design Principles\",\n \"\",\n \"1. **One company per session.** Never profile two companies in a\",\n \" single session, even if they came up together.\",\n \"2. **Public sources only.** Use the company's own site, press, product\",\n \" docs, job listings, and other public material. Do not attempt to\",\n \" access gated or paywalled content unless the invoking issue body\",\n \" explicitly authorizes it.\",\n \"3. **Filesystem durability.** The profile file is the deliverable. It\",\n \" is committed to disk before the profile issue closes. Downstream\",\n \" phases read from disk — never rely on session memory.\",\n \"4. **Generic over specific.** No hardcoded company types, taxonomies,\",\n \" or competitive assumptions. Use the generic company-type taxonomy\",\n \" below and let consuming projects override it.\",\n \"5. **Cite everything.** Every non-trivial factual claim in the profile\",\n \" must carry a source citation (URL plus access date).\",\n \"6. **Follow-up, don't widen scope.** If the session turns up adjacent\",\n \" research questions (a key person worth profiling, a product worth\",\n \" evaluating), emit a follow-up issue rather than expanding the\",\n \" profile beyond its scope. Notable people are handed off to the\",\n \" `people-profile` bundle via `people:research` issues; software\",\n \" products are handed off to the `software-profile` bundle via\",\n \" `software:research` issues.\",\n \"\",\n \"---\",\n \"\",\n \"## Company Type Taxonomy\",\n \"\",\n \"Pick exactly one type per company profile. The taxonomy is\",\n \"deliberately generic — consuming projects override it via\",\n \"`agentConfig.rules` if they need a domain-specific refinement.\",\n \"\",\n \"| Type | Use for |\",\n \"|------|---------|\",\n \"| `competitor` | Companies that sell a substitutable offering to the same customers. |\",\n \"| `industry-player` | Notable companies in the same industry that are not direct competitors (adjacent offerings, upstream/downstream, ecosystem). |\",\n \"| `software-vendor` | Companies whose software this project uses, integrates with, or evaluates as a build-vs-buy option. |\",\n \"| `customer` | Existing or prospective customers worth understanding in depth. |\",\n \"| `partner` | Strategic or channel partners, integrators, resellers, design partners. |\",\n \"| `investor` | Funds, angels, corporate investors relevant to fundraising or market positioning. |\",\n \"\",\n \"If the company plausibly fits two types, prefer the one that reflects\",\n \"the **reason the profile was requested**, and note the secondary type\",\n \"in the profile body.\",\n \"\",\n \"---\",\n \"\",\n \"## State Machine Overview\",\n \"\",\n \"```\",\n \"┌───────────────────┐ ┌──────────────────────┐ ┌───────────────────┐\",\n \"│ 1. RESEARCH │────▶│ 2. DRAFT PROFILE │────▶│ 3. FOLLOWUP │\",\n \"│ Collect public │ │ Write the structured │ │ Create follow-up │\",\n \"│ sources into a │ │ markdown profile to │ │ research issues │\",\n \"│ bounded notes │ │ the configured path │ │ for people and │\",\n \"│ file │ │ │ │ software surfaced │\",\n \"└───────────────────┘ └──────────────────────┘ └───────────────────┘\",\n \"```\",\n \"\",\n \"**Issue labels encode the phase:**\",\n \"\",\n \"| Label | Phase | Session work |\",\n \"|-------|-------|-------------|\",\n \"| `company:research` | 1. Research | Gather public sources. Write a bounded research-notes file. Create the draft issue. |\",\n \"| `company:draft` | 2. Draft | Read the research notes. Write the structured profile to `<PROFILES_DIR>`. Create the follow-up issue if warranted. |\",\n \"| `company:followup` | 3. Followup | Read the profile. Enqueue people/software research issues for items surfaced in the profile. |\",\n \"\",\n \"All issues also carry `type:company-profile` and a `status:*` label.\",\n \"\",\n \"**Issue count per company cycle:** 1 research + 1 draft + 0–1 followup =\",\n \"**2–3 sessions**. The followup phase is skipped when the profile did\",\n \"not surface any person or product worth follow-up research.\",\n \"\",\n \"**Shortened paths:**\",\n \"- Research phase determines the company is out of scope (not\",\n \" relevant, insufficient public material) → research issue closes\",\n \" with a justification and no downstream issues are created → **1 session**.\",\n \"- Short profile with no follow-ups needed → **2 sessions**.\",\n \"\",\n \"---\",\n \"\",\n \"## Configurable Paths\",\n \"\",\n \"The pipeline uses these placeholders. Consuming projects override the\",\n \"defaults by passing paths in the `/profile-company` skill invocation\",\n \"or by extending this rule in their own `agentConfig.rules`.\",\n \"\",\n \"| Placeholder | Meaning | Default |\",\n \"|-------------|---------|---------|\",\n \"| `<COMPANY_ROOT>` | Root folder for company profiles | `docs/companies/` |\",\n \"| `<PROFILES_DIR>` | Final company profile files | `<COMPANY_ROOT>/profiles/` |\",\n \"| `<NOTES_DIR>` | Research-notes files from Phase 1 | `<COMPANY_ROOT>/notes/` |\",\n \"| `<COMPANY_SLUG>` | Short kebab-case slug identifying the company | derived from the company name |\",\n \"| `<PEOPLE_PROFILES_DIR>` | Where existing people profiles live (for duplicate detection during followup) | `docs/people/profiles/` |\",\n \"| `<SOFTWARE_PROFILES_DIR>` | Where existing software profiles live (for duplicate detection during followup) | `docs/software/profiles/` |\",\n \"\",\n \"If `docs/project-context.md` specifies a different company-research\",\n \"tree (for example by reusing the research-pipeline deliverables\",\n \"folder), prefer that. Otherwise fall back to the defaults above.\",\n \"\",\n \"---\",\n \"\",\n \"## Agent Loop\",\n \"\",\n \"Run this loop exactly once per session. Never start a second issue.\",\n \"\",\n \"1. Claim one open `type:company-profile` issue using phase priority:\",\n \" `company:research` > `company:draft` > `company:followup`.\",\n \"2. Transition `status:ready` → `status:in-progress` and create the\",\n \" branch per your project's branch-naming convention.\",\n \"3. Execute the phase handler that matches the issue's `company:*`\",\n \" label.\",\n \"4. Commit, push, open a PR (if applicable), and close the issue per\",\n \" your project's PR workflow.\",\n \"\",\n \"---\",\n \"\",\n \"## Phase 1: Research (`company:research`)\",\n \"\",\n \"**Goal:** Gather public sources into a bounded research-notes file.\",\n \"\",\n \"**Budget:** Public web search only, unless the issue body authorizes\",\n \"additional sources. Write one notes file. Do not write the profile\",\n \"in this phase.\",\n \"\",\n \"### Steps\",\n \"\",\n \"1. **Read the issue body.** It should include:\",\n \" - The company name and website (if known)\",\n \" - The requested company type from the taxonomy above\",\n \" - The reason the profile was requested (framing — what does the\",\n \" invoking project want to learn?)\",\n \" - Optional: `<COMPANY_SLUG>` override, custom output paths\",\n \"\",\n \"2. **Derive `<COMPANY_SLUG>`** if not supplied — a 2–4 word kebab-case\",\n \" summary of the company name. Ensure the slug is not already in use\",\n \" under `<PROFILES_DIR>/` or `<NOTES_DIR>/`.\",\n \"\",\n \"3. **Gather sources.** Prioritize in this order:\",\n \" - The company's own website (home, product, pricing, about, careers)\",\n \" - Recent public press releases and reputable news coverage\",\n \" - Public product documentation and changelogs\",\n \" - Job listings (signals on stack, team size, and hiring focus)\",\n \" - Public profiles on well-known directories (Crunchbase, LinkedIn\",\n \" company page, GitHub organization) when the issue body authorizes\",\n \" them\",\n \"\",\n \"4. **Write a research-notes file** to\",\n \" `<NOTES_DIR>/<COMPANY_SLUG>.notes.md`:\",\n \"\",\n \" ```markdown\",\n \" ---\",\n ' title: \"Research Notes: <company name>\"',\n \" slug: <COMPANY_SLUG>\",\n \" company_type: <one of the taxonomy values>\",\n \" date: YYYY-MM-DD\",\n \" parent_issue: <N>\",\n \" ---\",\n \"\",\n \" # Research Notes: <company name>\",\n \"\",\n \" ## Framing\",\n \" <why this company was requested and what to learn>\",\n \"\",\n \" ## Raw Findings\",\n \" - <finding> — source: <citation>\",\n \"\",\n \" ## Candidate People of Interest\",\n \" - <name, role> — source: <citation>\",\n \"\",\n \" ## Candidate Products / Software of Interest\",\n \" - <product name> — source: <citation>\",\n \"\",\n \" ## Open Questions\",\n \" <anything the notes could not answer from public sources>\",\n \"\",\n \" ## Sources\",\n \" - <source URL or file path> — <date accessed>\",\n \" ```\",\n \"\",\n \"5. **Create the `company:draft` issue** with `Depends on: #<research-issue>`.\",\n \" Its body references the notes file path and the requested company\",\n \" type.\",\n \"\",\n \"6. **Commit and push** the notes file. Close the research issue.\",\n \"\",\n \"---\",\n \"\",\n \"## Phase 2: Draft Profile (`company:draft`)\",\n \"\",\n \"**Goal:** Write the structured company profile from the research notes.\",\n \"\",\n \"**Budget:** No new web searches unless explicitly needed to fill a\",\n \"gap the notes flagged. Write one profile file.\",\n \"\",\n \"### Steps\",\n \"\",\n \"1. **Read the research-notes file** referenced in the issue body.\",\n \"\",\n \"2. **Check for duplicates.** If `<PROFILES_DIR>/<COMPANY_SLUG>.md`\",\n \" already exists, open it and decide whether to update in place or\",\n \" flag a naming collision. Never silently overwrite a non-trivial\",\n \" existing profile.\",\n \"\",\n \"3. **Write the profile** to `<PROFILES_DIR>/<COMPANY_SLUG>.md` using\",\n \" the template below. All sections are required; use\",\n \" `_Not available in public sources._` when a section cannot be\",\n \" filled from the notes.\",\n \"\",\n \" ```markdown\",\n \" ---\",\n ' title: \"<company name>\"',\n \" slug: <COMPANY_SLUG>\",\n \" company_type: <one of the taxonomy values>\",\n \" website: <primary URL>\",\n \" date: YYYY-MM-DD\",\n \" parent_issue: <N>\",\n \" notes: <NOTES_DIR>/<COMPANY_SLUG>.notes.md\",\n \" ---\",\n \"\",\n \" # <company name>\",\n \"\",\n \" ## Summary\",\n \" <2–4 sentence elevator description: what they do, who they sell to>\",\n \"\",\n \" ## Classification\",\n \" - **Primary type:** <taxonomy value>\",\n \" - **Secondary type (if any):** <taxonomy value or `n/a`>\",\n \" - **Relevance to this project:** <1–2 sentences tying the company\",\n \" back to the framing from the notes>\",\n \"\",\n \" ## Offering\",\n \" - **Products / services:** <bullet list with one-line descriptions>\",\n \" - **Target customers:** <who they sell to>\",\n \" - **Pricing model:** <if disclosed>\",\n \"\",\n \" ## Company\",\n \" - **Founded:** <year if known>\",\n \" - **Headquarters:** <city, country if known>\",\n \" - **Size signals:** <headcount, funding stage, public/private — if known>\",\n \" - **Notable people:** <founders, relevant leaders>\",\n \"\",\n \" ## Technology Signals\",\n \" <stack hints from job listings, product docs, public engineering\",\n \" content — each bullet cited>\",\n \"\",\n \" ## Positioning / Differentiation\",\n \" <how they describe themselves and how they differ from adjacent\",\n \" companies — use their own language, cited, rather than inferred>\",\n \"\",\n \" ## Risks / Open Questions\",\n \" <what the profile could not answer; flag anything the follow-up\",\n \" phase should escalate>\",\n \"\",\n \" ## Follow-up Candidates\",\n \" - **People to profile:** <list of candidate name, role pairs>\",\n \" - **Products / software to evaluate:** <list of candidate product\",\n \" names>\",\n \"\",\n \" ## Sources\",\n \" - <source URL> — <date accessed>\",\n \" ```\",\n \"\",\n \"4. **Decide whether a follow-up issue is warranted.** Create a\",\n \" `company:followup` issue (depending on this draft issue) only if\",\n \" the profile lists at least one follow-up candidate. Otherwise,\",\n \" note in the draft issue's closing comment that no follow-up is\",\n \" needed.\",\n \"\",\n \"5. **Commit and push** the profile file. Close the draft issue.\",\n \"\",\n \"---\",\n \"\",\n \"## Phase 3: Followup (`company:followup`)\",\n \"\",\n \"**Goal:** Create downstream research issues for the people and\",\n \"software products surfaced in the profile. Hand the candidates off to\",\n \"the `people-profile` and `software-profile` bundles so they can be\",\n \"researched independently.\",\n \"\",\n \"**Budget:** No new research. Read the profile, enqueue issues, close\",\n \"the phase. Markdown cross-references in the profile's\",\n \"`## Follow-up Candidates` section are preserved — issue creation is\",\n \"**additive** on top of the existing notes-only behavior.\",\n \"\",\n \"### Steps\",\n \"\",\n \"1. **Read the profile file** referenced in the issue body.\",\n \"\",\n \"2. **Enqueue a `people:research` issue per candidate** under\",\n \" `Follow-up Candidates > People to profile` that is worth\",\n \" downstream research. Each issue must carry:\",\n \"\",\n \" - `type:people-profile`\",\n \" - `people:research`\",\n \" - `priority:medium`\",\n \" - `status:ready`\",\n \"\",\n \" The issue body must include:\",\n \" - A **discovery source** line naming this company profile\",\n \" (`Discovered while profiling: <company name>`)\",\n \" - A link to the company profile path (`Company profile: <PROFILES_DIR>/<COMPANY_SLUG>.md`)\",\n \" - Enough identifying metadata — full name, role/title, and\",\n \" employing company — that the `people-profile-analyst` agent can\",\n \" begin research without revisiting this company profile\",\n \"\",\n \"3. **Enqueue a `software:research` issue per candidate** under\",\n \" `Follow-up Candidates > Products / software to evaluate` that is\",\n \" worth downstream research. Each issue must carry:\",\n \"\",\n \" - `type:software-profile`\",\n \" - `software:research`\",\n \" - `priority:medium`\",\n \" - `status:ready`\",\n \"\",\n \" The issue body must include:\",\n \" - A **discovery source** line naming this company profile\",\n \" (`Discovered while profiling: <company name>`)\",\n \" - A link to the company profile path (`Company profile: <PROFILES_DIR>/<COMPANY_SLUG>.md`)\",\n \" - Enough identifying metadata — product name and vendor (usually\",\n \" this company if it builds the product, otherwise the upstream\",\n \" vendor) — that the `software-profile-analyst` agent can begin\",\n \" research without revisiting this company profile\",\n \"\",\n \"4. **Avoid duplicates.** Before opening a `people:research` or\",\n \" `software:research` issue, verify no existing profile covers the\",\n \" candidate:\",\n \"\",\n \" - People: check `<PEOPLE_PROFILES_DIR>/` for a matching profile\",\n \" file (by derived slug or by searching the directory for the\",\n \" person's name). If a profile exists, reuse it as a cross-reference\",\n \" only — **do not** open a new `people:research` issue.\",\n \" - Software: check `<SOFTWARE_PROFILES_DIR>/` the same way. If a\",\n \" profile exists, reuse it as a cross-reference only — **do not**\",\n \" open a new `software:research` issue.\",\n \" - Also scan open issues carrying the matching `people:research` or\",\n \" `software:research` label so this phase never re-opens research\",\n \" that is already queued.\",\n \"\",\n \"5. **Exercise restraint.** Only create downstream issues for people\",\n \" and software products that are **genuinely relevant** to the\",\n \" framing of this profile — executives, founders, and decision-makers\",\n \" for people; products the company builds or materially depends on\",\n \" for software. Do **not** open issues for every name mentioned in\",\n \" passing, every SaaS tool listed in a job ad, or every tangential\",\n \" partner. When in doubt, leave the candidate as a markdown\",\n \" cross-reference in the profile and skip the downstream issue.\",\n \"\",\n \"6. **Assume the peers are present.** This pipeline assumes the\",\n \" `people-profile` and `software-profile` bundles are enabled in the\",\n \" consuming project. If a consuming project has disabled one of\",\n \" them, flag the followup issue with `status:needs-attention` and\",\n \" list the candidates that could not be routed — never invent an\",\n \" alternative label taxonomy.\",\n \"\",\n \"7. **Cross-link** — update the profile's `## Follow-up Candidates`\",\n \" section so each entry references its newly-created issue number\",\n \" (or the existing profile path, for candidates that were skipped\",\n \" because a profile already exists).\",\n \"\",\n \"8. **Commit and push** (if the profile was updated). Close the\",\n \" followup issue.\",\n \"\",\n \"---\",\n \"\",\n \"## Output Boundaries\",\n \"\",\n \"This agent writes **only** to:\",\n \"\",\n \"- `<NOTES_DIR>/` — research-notes files (Phase 1)\",\n \"- `<PROFILES_DIR>/` — company profiles (Phase 2, updated in Phase 3)\",\n \"\",\n \"In Phase 3, this agent also **creates `people:research` and\",\n \"`software:research` issues** for people and software products\",\n \"surfaced in the profile. It never writes the downstream profiles\",\n \"themselves — those are the responsibility of the\",\n \"`people-profile-analyst` and `software-profile-analyst` agents, which\",\n \"pick up the issues this pipeline creates.\",\n \"\",\n \"The pipeline produces **company profiles and notes only**. Deeper\",\n \"research on people or products is delegated to downstream research\",\n \"pipelines via `people:research` and `software:research` issues — this\",\n \"agent never writes person profiles, software profiles, product\",\n \"evaluations, or comparative analyses itself. Keep this boundary clean\",\n \"so the company-profile pipeline stays generic.\",\n \"\",\n \"---\",\n \"\",\n \"## Rules\",\n \"\",\n \"- **One company per session.** Never profile two companies back-to-back.\",\n \"- **Persist before closing.** Every phase must write its output file\",\n \" before closing its issue.\",\n \"- **Cite everything.** Profile claims without source citations do not\",\n \" belong in the deliverable.\",\n \"- **No assumed competition.** Never call a company a competitor unless\",\n \" the invoking issue body or the consuming project's configuration\",\n \" says so.\",\n \"- **Delegate, don't duplicate.** People and software products\",\n \" surfaced during profiling are handed off to the `people-profile`\",\n \" and `software-profile` bundles via `people:research` and\",\n \" `software:research` issues in Phase 3 — never inlined as person or\",\n \" software profiles in this pipeline.\",\n \"- **Check before enqueueing.** Before opening a `people:research` or\",\n \" `software:research` issue, verify no existing profile or open\",\n \" research issue already covers the candidate. Reuse existing\",\n \" profiles as cross-references rather than re-queuing research.\",\n \"- **Restrain the queue.** Only enqueue downstream research for people\",\n \" and products that are genuinely relevant to the framing of this\",\n \" profile. Do not open issues for every name or product mentioned in\",\n \" passing.\",\n \"- **Produce profiles, not requirement or evaluation documents.** Do\",\n \" not open `type:requirement` or formal evaluation issues from this\",\n \" pipeline. Follow-up research is scoped through `people:research`\",\n \" and `software:research` only.\",\n ].join(\"\\n\"),\n};\n\n/** Skill that kicks off a company profile cycle. */\nconst profileCompanySkill: AgentSkill = {\n name: \"profile-company\",\n description:\n \"Kick off a company-profile pipeline. Creates a company:research issue for the given company and dispatches Phase 1 (Research) in the company-profile-analyst agent.\",\n disableModelInvocation: true,\n userInvocable: true,\n context: \"fork\",\n agent: \"company-profile-analyst\",\n platforms: { cursor: { exclude: true } },\n instructions: [\n \"# Profile Company\",\n \"\",\n \"Kick off a company-profile pipeline. Creates a `company:research`\",\n \"issue carrying the company name, type, and framing, then dispatches\",\n \"Phase 1 (Research) in the company-profile-analyst agent.\",\n \"\",\n \"## Usage\",\n \"\",\n \"/profile-company <company-name>\",\n \"\",\n \"Optional extensions in the issue body:\",\n \"- `type: <competitor | industry-player | software-vendor | customer |\",\n \" partner | investor>` — override the default type inference\",\n \"- `website: <url>` — canonical website if not obvious from the name\",\n \"- `framing: <text>` — why this profile was requested and what to learn\",\n \"- `slug: <kebab-case>` — override the derived company slug\",\n \"- `sources: <list>` — additional authorized sources beyond public web\",\n \"\",\n \"## Default Paths\",\n \"\",\n \"If the project has no override in `docs/project-context.md` or\",\n \"`agentConfig.rules`, outputs land under:\",\n \"\",\n \"- `docs/companies/notes/<slug>.notes.md`\",\n \"- `docs/companies/profiles/<slug>.md`\",\n \"\",\n \"## Steps\",\n \"\",\n \"1. Create a `company:research` issue with `type:company-profile`,\",\n \" `priority:medium`, and `status:ready`. Body must include the\",\n \" company name, selected type, framing, and any overrides.\",\n \"2. Execute Phase 1 (Research) of the company-profile-analyst agent.\",\n \"3. Phase 1 creates the `company:draft` issue. Phase 2 may create a\",\n \" `company:followup` issue. Each downstream issue declares its\",\n \" `Depends on:` predecessor.\",\n \"\",\n \"## Output\",\n \"\",\n \"- A research-notes file under the project's notes directory\",\n \"- A single company profile under the profiles directory\",\n \"- `people:research` issues for notable people surfaced in the profile\",\n \" (handed off to the `people-profile` bundle)\",\n \"- `software:research` issues for software products surfaced in the\",\n \" profile (handed off to the `software-profile` bundle)\",\n \"- This pipeline produces **company profiles only** — it does not\",\n \" write person profiles, software profiles, product evaluations, or\",\n \" comparative analyses itself.\",\n ].join(\"\\n\"),\n};\n\n/**\n * Company-profile bundle — enabled by default.\n *\n * Consuming projects can disable it with\n * `excludeBundles: [\"company-profile\"]`. `appliesWhen` always returns\n * `true` per the operating-system directive that bundles assume peers\n * are present — in Phase 3 this bundle hands work off to\n * `people-profile` (via `people:research`) and `software-profile` (via\n * `software:research`).\n *\n * Ships a sub-agent (`company-profile-analyst`), a user-invocable skill\n * (`/profile-company`), and `type:company-profile` plus `company:*`\n * phase labels.\n */\nexport const companyProfileBundle: AgentRuleBundle = {\n name: \"company-profile\",\n description:\n \"Company research and profiling pipeline: research, draft profile, followup. Enabled by default; domain-neutral; filesystem-durable between phases. Phase 3 (Followup) hands surfaced people and software products off to the `people-profile` and `software-profile` bundles via `people:research` and `software:research` issues.\",\n appliesWhen: () => true,\n rules: [\n {\n name: \"company-profile-workflow\",\n description:\n \"Describes the 3-phase company-profile pipeline, the company:* label taxonomy, and the boundary against downstream research agents.\",\n scope: AGENT_RULE_SCOPE.ALWAYS,\n content: [\n \"# Company Profile Workflow\",\n \"\",\n \"Use `/profile-company <company-name>` to kick off a company\",\n \"research and profiling pipeline. The pipeline runs in up to 3\",\n \"phases — research, draft, followup — each tracked by its own\",\n \"GitHub issue labeled `company:research`, `company:draft`, or\",\n \"`company:followup`. All issues carry `type:company-profile`.\",\n \"\",\n \"The pipeline produces **company profiles only**. Deeper research\",\n \"on notable people and software products surfaced while profiling\",\n \"is delegated to the `people-profile` and `software-profile`\",\n \"bundles via `people:research` and `software:research` issues\",\n \"opened during Phase 3 (Followup).\",\n \"\",\n \"See the `company-profile-analyst` agent definition for full\",\n \"workflow details, default paths, the company-type taxonomy, and\",\n \"phase-by-phase instructions.\",\n ].join(\"\\n\"),\n platforms: {\n cursor: { exclude: true },\n },\n tags: [\"workflow\"],\n },\n ],\n skills: [profileCompanySkill],\n subAgents: [companyProfileAnalystSubAgent],\n labels: [\n {\n name: \"type:company-profile\",\n color: \"0E8A16\",\n description:\n \"Work that produces or maintains a company profile or its research notes\",\n },\n {\n name: \"company:research\",\n color: \"C5DEF5\",\n description:\n \"Phase 1: gather public sources about a company into a research-notes file\",\n },\n {\n name: \"company:draft\",\n color: \"BFDADC\",\n description:\n \"Phase 2: write the structured company profile from research notes\",\n },\n {\n name: \"company:followup\",\n color: \"D4C5F9\",\n description:\n \"Phase 3: enqueue follow-up research issues for people and products surfaced in the profile\",\n },\n ],\n};\n","import { GitHub } from \"projen/lib/github\";\nimport { AgentRuleBundle } from \"../agent-config-options\";\nimport { AGENT_RULE_SCOPE } from \"../types\";\nimport { hasComponent } from \"./utils\";\n\n/**\n * GitHub workflow bundle — auto-detected when the project has a GitHub component.\n */\nexport const githubWorkflowBundle: AgentRuleBundle = {\n name: \"github-workflow\",\n description: \"GitHub issue and PR workflow automation patterns\",\n appliesWhen: (project) => hasComponent(project, GitHub),\n rules: [\n {\n name: \"issue-workflow\",\n description: \"Automated workflow for starting work on a GitHub issue\",\n scope: AGENT_RULE_SCOPE.ALWAYS,\n content: [\n \"# Issue Workflow\",\n \"\",\n '## \"Work on issue X\" Automation',\n \"\",\n \"When the user says **work on issue X** (or similar), invoke the `issue-worker` agent in interactive mode, passing the issue number in the prompt. Do not perform the branch creation, issue fetching, or planning steps yourself — the agent handles the full workflow (claim, branch, plan, implement, PR) and will pause for your approval at the appropriate checkpoints.\",\n ].join(\"\\n\"),\n tags: [\"workflow\"],\n },\n {\n name: \"create-issue-workflow\",\n description: \"Automated workflow for creating a new GitHub issue\",\n scope: AGENT_RULE_SCOPE.ALWAYS,\n content: [\n \"# Create Issue Workflow\",\n \"\",\n '## \"Create an issue\" Automation',\n \"\",\n \"When the user says **create an issue** (or similar), follow these steps exactly:\",\n \"\",\n \"1. **Determine the issue type prefix** from the user's description:\",\n \" - `epic:` — Large initiatives spanning multiple child issues\",\n \" - `feat:` — New features or functionality\",\n \" - `fix:` — Bug fixes\",\n \" - `chore:` — Maintenance: deps, tooling, config\",\n \" - `docs:` — Documentation-only work\",\n \" - `refactor:` — Code restructure, no behavior change\",\n \" - `release:` — Release preparation, version bumps\",\n \" - `hotfix:` — Urgent production fixes\",\n \" - If unclear, ask the user which type applies\",\n \"2. **Compose the issue title** in the format: `<type>: <short description>`\",\n \"3. **Determine the GitHub issue type** based on the prefix:\",\n \" - `epic:` → Epic\",\n \" - `feat:` → Feature\",\n \" - `fix:` → Bug\",\n \" - `chore:`, `docs:`, `refactor:`, `release:`, `hotfix:` → Task\",\n \"4. **Identify prerequisite issues** — if the user mentions dependencies or blockers, include a **Dependencies** section in the body with `Depends on: #<issue-number>`\",\n \"5. **Determine labels** — every issue must be created with the following labels:\",\n \" - **`type:*`** — derived from the issue title prefix:\",\n \" - `epic:` → `type:feat`\",\n \" - `feat:` → `type:feat`\",\n \" - `fix:` → `type:fix`\",\n \" - `chore:` → `type:chore`\",\n \" - `docs:` → `type:docs`\",\n \" - `refactor:` → `type:refactor`\",\n \" - `release:` → `type:release`\",\n \" - `hotfix:` → `type:hotfix`\",\n ' - **`priority:*`** — infer from the user\\'s description when possible (e.g., \"urgent\"/\"critical\" → `priority:critical`, \"important\" → `priority:high`, \"minor\"/\"low priority\" → `priority:low`). If the priority is unclear, ask the user before creating the issue. Valid values: `priority:critical`, `priority:high`, `priority:medium`, `priority:low`, `priority:trivial`',\n \" - **`status:ready`** — always add unless the issue has dependencies or blockers, in which case use `status:blocked`\",\n \"6. **Create the issue** using `gh issue create`:\",\n \" - `--title '<type>: <description>'`\",\n \" - `--body '<issue body>'`\",\n \" - `--label '<type-label>' --label '<priority-label>' --label '<status-label>'`\",\n \"7. **Set the GitHub issue type** via the GraphQL `updateIssueIssueType` mutation:\",\n \" - Look up the issue's node ID: `gh issue view <issue-number> --json id -q .id`\",\n \" - Look up the repo's issue type node IDs (one-time, can be cached):\",\n \"\",\n \" ```sh\",\n \" gh api graphql -f query='query($owner:String!,$repo:String!){repository(owner:$owner,name:$repo){issueTypes(first:20){nodes{id name}}}}' -f owner=<owner> -f repo=<repo>\",\n \" ```\",\n \"\",\n \" - Apply the chosen type to the issue:\",\n \"\",\n \" ```sh\",\n \" gh api graphql -f query='mutation($issueId:ID!,$typeId:ID!){updateIssueIssueType(input:{issueId:$issueId,issueTypeId:$typeId}){issue{number issueType{name}}}}' -f issueId=<issue-node-id> -f typeId=<issue-type-node-id>\",\n \" ```\",\n \"\",\n \"### Issue Body Template\",\n \"\",\n \"```markdown\",\n \"## Summary\",\n \"\",\n \"<1-3 sentences describing the issue>\",\n \"\",\n \"## Details\",\n \"\",\n \"<Detailed description, acceptance criteria, or reproduction steps as appropriate>\",\n \"\",\n \"## Dependencies\",\n \"\",\n \"Depends on: #<issue-number> (if any, otherwise omit this section)\",\n \"```\",\n \"\",\n \"### Important\",\n \"\",\n \"- Always use the conventional prefix in the issue title\",\n \"- Always assign the correct GitHub issue type via the `updateIssueIssueType` GraphQL mutation (step 7) — never via `gh issue create --type`\",\n \"- Always include `type:*`, `priority:*`, and `status:*` labels\",\n \"- If the user does not specify a type, ask before creating the issue\",\n \"- If the priority cannot be inferred from the description, ask the user before creating the issue\",\n \"- Keep titles concise and descriptive\",\n ].join(\"\\n\"),\n tags: [\"workflow\"],\n },\n {\n name: \"pr-workflow\",\n description: \"Automated workflow for opening a pull request\",\n scope: AGENT_RULE_SCOPE.ALWAYS,\n content: [\n \"# PR Workflow\",\n \"\",\n '## \"Open a PR\" Automation',\n \"\",\n \"When the user says **open a PR** (or similar), follow these steps exactly:\",\n \"\",\n \"1. **Regenerate project files** — run `npx projen` then `pnpm install` to ensure all generated files are up to date. Check `git diff` — if there are changes, commit them before proceeding.\",\n \"2. **Run the full monorepo build** — run `pnpm build:all` to compile, lint, and test all packages (mirrors the CI pipeline). This command requires the user to be authenticated to AWS on the prod account used for Turborepo remote caching (`readonlyaccess-prod-525259625215-us-east-1` profile). If the command fails due to AWS credentials, ask the user to authenticate first. If the build produces changes to turbo inputs (typically snapshot files or ESLint auto-fixes), commit those changes and run `pnpm build:all` again — the build must complete cleanly with no uncommitted changes.\",\n \"3. **Check for uncommitted changes** — if any exist, commit them with a conventional commit message\",\n \"4. **Pull and rebase from the default branch** — run `git pull origin {{repository.defaultBranch}} --rebase` to incorporate the latest changes and resolve any conflicts before pushing\",\n \"5. **Push the branch** to origin: `git push -u origin <branch>`\",\n \"6. **Create the PR** using `gh pr create`:\",\n \" - **Title**: use a conventional commit style title (e.g., `feat(scope): short description`)\",\n \" - **Body**: include `Closes #<issue-number>` (derived from the branch name) and a brief summary of changes\",\n \"7. **Delegate review and merge to the `pr-reviewer` sub-agent.** After the PR is created, invoke the `/review-pr <pr-number>` skill (or otherwise hand the new PR number to the `pr-reviewer` sub-agent). The reviewer verifies the diff against the linked issue's acceptance criteria and enables squash auto-merge when all checks pass. Do **not** run `gh pr merge --auto` yourself — review/merge policy lives solely in the `pr-reviewer` agent.\",\n \"\",\n \"### PR Body Template\",\n \"\",\n \"```markdown\",\n \"## Summary\",\n \"\",\n \"<1-3 bullet points describing what changed and why>\",\n \"\",\n \"Closes #<issue-number>\",\n \"\",\n \"## Test Plan\",\n \"\",\n \"- [ ] Tests pass locally\",\n \"- [ ] Relevant changes have been reviewed\",\n \"```\",\n \"\",\n \"### Important\",\n \"\",\n \"- Always derive the issue number from the branch name (e.g., `feat/42-add-login` → `#42`)\",\n \"- Use conventional commit format for the PR title\",\n \"- Delegate merge to the `pr-reviewer` sub-agent — do not merge manually and do not enable auto-merge directly\",\n ].join(\"\\n\"),\n tags: [\"workflow\"],\n },\n ],\n};\n","import { AgentRuleBundle } from \"../agent-config-options\";\nimport { PROJECT_CONTEXT_READER_SECTION } from \"./project-context\";\nimport {\n AGENT_MODEL,\n AGENT_RULE_SCOPE,\n AgentSkill,\n AgentSubAgent,\n} from \"../types\";\n\n/**\n * Sub-agent that discovers candidate industry verticals, evaluates each\n * against a configurable capability/fit rubric, and plans downstream\n * research for verticals that clear the threshold.\n *\n * The prompt deliberately avoids hardcoded domains, companies, or source\n * projects. Consumers configure scoring inputs, threshold values, output\n * paths, and the fit rubric via the skill invocation and by extending\n * the rule in their own `agentConfig.rules`.\n */\nconst industryDiscoveryAnalystSubAgent: AgentSubAgent = {\n name: \"industry-discovery-analyst\",\n description:\n \"Discovers candidate industry verticals, scores each against a configurable capability/fit rubric, and creates planning issues for verticals that clear the threshold. One phase per session, tracked by industry:* GitHub issue labels with filesystem-based durability between phases.\",\n model: AGENT_MODEL.POWERFUL,\n maxTurns: 80,\n platforms: { cursor: { exclude: true } },\n prompt: [\n \"# Industry Discovery Analyst Agent\",\n \"\",\n \"You run a structured industry-discovery pipeline: enumerate candidate\",\n \"industry verticals, score each against a configurable capability/fit\",\n \"rubric, and plan downstream research for the verticals that clear the\",\n \"configured threshold. Each phase runs as its **own agent session**,\",\n \"triggered by a GitHub issue with an `industry:*` phase label. You\",\n \"handle exactly **one phase per session** — read the issue to determine\",\n \"which phase to execute.\",\n \"\",\n \"This agent is **domain-neutral**. It makes no assumptions about what\",\n \"the consuming project sells, which industries matter, or what the\",\n \"scoring rubric should weight. All domain-specific vocabulary, scoring\",\n \"inputs, output locations, and threshold values come from the invoking\",\n \"issue body, `docs/project-context.md`, or the consuming project's\",\n \"configuration.\",\n \"\",\n \"Follow your project's shared agent conventions (`AGENTS.md`,\",\n \"`CLAUDE.md`, or equivalent) for all commit, branch, and PR rules.\",\n \"\",\n \"---\",\n \"\",\n ...PROJECT_CONTEXT_READER_SECTION,\n \"## Design Principles\",\n \"\",\n \"1. **Discover broadly, evaluate narrowly.** Phase 1 casts a wide net\",\n \" for candidate verticals; Phase 2 applies the rubric to each one;\",\n \" Phase 3 only plans downstream research for verticals that clear the\",\n \" threshold.\",\n \"2. **Filesystem durability.** Every phase persists its output to a\",\n \" file on disk before closing its issue. Downstream phases read those\",\n \" files — never rely on session memory.\",\n \"3. **Issue graph = state machine.** Phase ordering is encoded with\",\n \" `Depends on: #N` links between phase issues. A phase runs only\",\n \" after its predecessor is closed.\",\n \"4. **Generic over specific.** No hardcoded industry taxonomies,\",\n \" companies, or source projects. Use placeholders that the skill\",\n \" invocation or consuming project fills in.\",\n \"5. **Configurable rubric.** The fit rubric — criteria, weights, and\",\n \" threshold — comes from `docs/project-context.md` or the invoking\",\n \" issue body. Never invent weights or pass/fail cutoffs without an\",\n \" authoritative source.\",\n \"6. **Planning only.** This pipeline produces candidate lists,\",\n \" evaluations, and planning issues — it does not itself perform the\",\n \" downstream research. Research is delegated to the\",\n \" `research-pipeline` bundle via `research:scope` issues.\",\n \"\",\n \"---\",\n \"\",\n \"## State Machine Overview\",\n \"\",\n \"```\",\n \"┌──────────────────┐ ┌────────────────────┐ ┌──────────────────┐\",\n \"│ 1. DISCOVER │────▶│ 2. EVALUATE │────▶│ 3. PLAN │\",\n \"│ Enumerate │ │ Score each │ │ For each vertical│\",\n \"│ candidate │ │ candidate against │ │ that clears the │\",\n \"│ industry │ │ the configured fit │ │ threshold, open │\",\n \"│ verticals into a │ │ rubric; write an │ │ a research:scope │\",\n \"│ bounded │ │ evaluation file │ │ issue downstream │\",\n \"│ candidate file │ │ with per-candidate │ │ │\",\n \"│ │ │ scores │ │ │\",\n \"└──────────────────┘ └────────────────────┘ └──────────────────┘\",\n \"```\",\n \"\",\n \"**Issue labels encode the phase:**\",\n \"\",\n \"| Label | Phase | Session work |\",\n \"|-------|-------|-------------|\",\n \"| `industry:discover` | 1. Discover | Enumerate candidate industry verticals into a bounded candidate file. Create the evaluate issue. |\",\n \"| `industry:evaluate` | 2. Evaluate | Score each candidate against the fit rubric. Write an evaluation file. Create the plan issue. |\",\n \"| `industry:plan` | 3. Plan | Read the evaluation. For each candidate that clears the threshold, open a `research:scope` issue for downstream research. |\",\n \"\",\n \"All issues also carry `type:industry-discovery` and a `status:*` label.\",\n \"\",\n \"**Issue count per discovery cycle:** 1 discover + 1 evaluate + 1 plan =\",\n \"**3 sessions**, plus `M` `research:scope` issues created by Phase 3,\",\n \"where `M` is the number of verticals that clear the threshold.\",\n \"\",\n \"**Shortened paths:**\",\n \"- Discover phase determines the scope is unworkable (no candidate\",\n \" verticals, scope out of bounds) → discover issue closes with a\",\n \" justification and no downstream issues are created → **1 session**.\",\n \"- Evaluate phase determines no candidate clears the threshold → plan\",\n \" issue closes with a justification and no `research:scope` issues are\",\n \" created → **3 sessions, 0 downstream issues**.\",\n \"\",\n \"---\",\n \"\",\n \"## Configurable Paths\",\n \"\",\n \"The pipeline uses these placeholders. Consuming projects override the\",\n \"defaults by passing paths in the `/discover-industries` skill\",\n \"invocation or by extending this rule in their own `agentConfig.rules`.\",\n \"\",\n \"| Placeholder | Meaning | Default |\",\n \"|-------------|---------|---------|\",\n \"| `<INDUSTRY_ROOT>` | Root folder for all industry-discovery outputs | `docs/industries/` |\",\n \"| `<CANDIDATES_DIR>` | Candidate-list files (Phase 1) | `<INDUSTRY_ROOT>/candidates/` |\",\n \"| `<EVALUATIONS_DIR>` | Evaluation files with per-candidate scores (Phase 2) | `<INDUSTRY_ROOT>/evaluations/` |\",\n \"| `<PLANS_DIR>` | Plan files summarizing downstream research (Phase 3) | `<INDUSTRY_ROOT>/plans/` |\",\n \"| `<DISCOVERY_SLUG>` | Short kebab-case slug identifying one discovery cycle | derived from the scope |\",\n \"\",\n \"If `docs/project-context.md` specifies a different industry-discovery\",\n \"tree, prefer that. Otherwise fall back to the defaults above.\",\n \"\",\n \"---\",\n \"\",\n \"## Fit Rubric Convention\",\n \"\",\n \"The fit rubric is the scoring framework Phase 2 uses to evaluate each\",\n \"candidate vertical. It is **not invented by this agent** — it must come\",\n \"from an authoritative source, resolved in this order:\",\n \"\",\n \"1. **Invoking issue body.** If the issue body includes a `## Fit\",\n \" Rubric` section, use it verbatim.\",\n \"2. **`docs/project-context.md`.** If the project context file includes\",\n \" a `## Industry Fit Rubric` section, use it.\",\n \"3. **Default scaffold.** If neither source defines a rubric, write a\",\n \" placeholder rubric with `TODO:` weights and flag the evaluate issue\",\n \" with `status:needs-attention` — do not silently invent weights.\",\n \"\",\n \"The rubric has this shape:\",\n \"\",\n \"```markdown\",\n \"## Industry Fit Rubric\",\n \"\",\n \"| Criterion | Weight | Description |\",\n \"|-----------|--------|-------------|\",\n \"| <name> | <0.0–1.0> | <what high vs. low looks like> |\",\n \"\",\n \"**Threshold:** <0.0–1.0> — verticals scoring at or above this value\",\n \"advance to Phase 3 (Plan).\",\n \"\",\n \"**Scoring scale:** per-criterion score is 0.0–1.0; the final score is\",\n \"the weighted average of the criteria.\",\n \"```\",\n \"\",\n \"---\",\n \"\",\n \"## Agent Loop\",\n \"\",\n \"Run this loop exactly once per session. Never start a second issue.\",\n \"\",\n \"1. Claim one open `type:industry-discovery` issue using phase\",\n \" priority: `industry:discover` > `industry:evaluate` > `industry:plan`.\",\n \"2. Transition `status:ready` → `status:in-progress` and create the\",\n \" branch per your project's branch-naming convention.\",\n \"3. Execute the phase handler that matches the issue's `industry:*`\",\n \" label.\",\n \"4. Commit, push, open a PR (if applicable), and close the issue per\",\n \" your project's PR workflow.\",\n \"\",\n \"---\",\n \"\",\n \"## Phase 1: Discover (`industry:discover`)\",\n \"\",\n \"**Goal:** Enumerate candidate industry verticals into a bounded\",\n \"candidate file.\",\n \"\",\n \"**Budget:** Limited discovery research. Read the scope, the project\",\n \"context, and any cited source material. Write one candidate file and\",\n \"create one evaluate issue. Do not score in this phase.\",\n \"\",\n \"### Steps\",\n \"\",\n \"1. **Read the discovery scope** from the issue body. The body should\",\n \" include:\",\n \" - The scope statement (what kind of industry verticals to look for,\",\n \" what to exclude)\",\n \" - Authorized source categories (e.g. public web, industry reports,\",\n \" a cited local file path) — if absent, default to public web only\",\n \" - Optional: `<DISCOVERY_SLUG>` override, custom output paths,\",\n \" candidate-count hints (default target: 8–20 candidates)\",\n \"\",\n \"2. **Derive `<DISCOVERY_SLUG>`** if not supplied — a 3–5 word\",\n \" kebab-case summary of the scope. Ensure the slug is not already in\",\n \" use under `<CANDIDATES_DIR>/`.\",\n \"\",\n \"3. **Enumerate candidate verticals.** Aim for 8–20 distinct candidate\",\n \" verticals unless the scope states otherwise. Each candidate should:\",\n \" - Be a recognizable industry vertical or sub-vertical (not a single\",\n \" company, not a product category)\",\n \" - Be within the scope defined in the issue\",\n \" - Have at least a brief description and one cited source\",\n \"\",\n \"4. **Write the candidate file** to\",\n \" `<CANDIDATES_DIR>/<DISCOVERY_SLUG>.candidates.md`:\",\n \"\",\n \" ```markdown\",\n \" ---\",\n ' title: \"Industry Candidates: <scope>\"',\n \" slug: <DISCOVERY_SLUG>\",\n \" date: YYYY-MM-DD\",\n \" parent_issue: <N>\",\n \" candidate_count: <N>\",\n \" ---\",\n \"\",\n \" # Industry Candidates: <scope>\",\n \"\",\n \" ## Scope\",\n \" <verbatim scope statement from the issue>\",\n \"\",\n \" ## Authorized Sources\",\n \" - <source category or path>\",\n \"\",\n \" ## Candidates\",\n \" ### <vertical name>\",\n \" - **Description:** <1–2 sentences>\",\n \" - **Why in scope:** <why this vertical matches the scope>\",\n \" - **Sources:** <citations>\",\n \"\",\n \" ## Out of Scope\",\n \" <verticals deliberately excluded from this cycle and why>\",\n \" ```\",\n \"\",\n \"5. **Create one `industry:evaluate` issue** with\",\n \" `Depends on: #<discover-issue>`. Its body references the candidate\",\n \" file path and the fit rubric source (invoking issue, project\",\n \" context, or scaffold).\",\n \"\",\n \"6. **Commit and push** the candidate file. Close the discover issue.\",\n \"\",\n \"---\",\n \"\",\n \"## Phase 2: Evaluate (`industry:evaluate`)\",\n \"\",\n \"**Goal:** Score every candidate against the fit rubric and produce an\",\n \"evaluation file.\",\n \"\",\n \"**Budget:** No broad exploratory research — evaluate what the candidate\",\n \"file already captured, pulling targeted clarifications only when a\",\n \"criterion cannot be scored. Write one evaluation file.\",\n \"\",\n \"### Steps\",\n \"\",\n \"1. **Read the candidate file** referenced in the issue body.\",\n \"\",\n \"2. **Resolve the fit rubric** per the Fit Rubric Convention above.\",\n \" If neither the invoking issue nor `docs/project-context.md` defines\",\n \" a rubric, emit a scaffold and flag `status:needs-attention` — do not\",\n \" silently invent weights or thresholds.\",\n \"\",\n \"3. **Score each candidate.** For each criterion, assign a 0.0–1.0\",\n \" score and cite at least one source for the score. Compute the\",\n \" weighted-average final score.\",\n \"\",\n \"4. **Write the evaluation file** to\",\n \" `<EVALUATIONS_DIR>/<DISCOVERY_SLUG>.evaluation.md`:\",\n \"\",\n \" ```markdown\",\n \" ---\",\n ' title: \"Industry Evaluation: <scope>\"',\n \" slug: <DISCOVERY_SLUG>\",\n \" date: YYYY-MM-DD\",\n \" parent_issue: <N>\",\n \" candidates_source: <CANDIDATES_DIR>/<DISCOVERY_SLUG>.candidates.md\",\n \" threshold: <0.0–1.0>\",\n \" ---\",\n \"\",\n \" # Industry Evaluation: <scope>\",\n \"\",\n \" ## Fit Rubric\",\n \" <verbatim rubric table, including weights and threshold>\",\n \"\",\n \" ## Scored Candidates\",\n \"\",\n \" | Vertical | Weighted Score | Clears Threshold |\",\n \" |----------|----------------|------------------|\",\n \" | <name> | 0.73 | yes |\",\n \"\",\n \" ### <vertical name> — 0.73\",\n \" - **<criterion>:** 0.8 — <one-line justification + citation>\",\n \" - **<criterion>:** 0.6 — <one-line justification + citation>\",\n \" - **Notes:** <anything the rubric could not capture>\",\n \"\",\n \" ## Gaps / Open Questions\",\n \" <criteria that could not be scored for one or more candidates>\",\n \" ```\",\n \"\",\n \"5. **Create one `industry:plan` issue** with\",\n \" `Depends on: #<evaluate-issue>`. Its body references the evaluation\",\n \" file path and lists the verticals that clear the threshold (if any).\",\n \"\",\n \"6. **Commit and push** the evaluation file. Close the evaluate issue.\",\n \"\",\n \"---\",\n \"\",\n \"## Phase 3: Plan (`industry:plan`)\",\n \"\",\n \"**Goal:** For each vertical that clears the threshold, open a\",\n \"`research:scope` issue so the `research-pipeline` bundle can pick it up\",\n \"and produce a research deliverable.\",\n \"\",\n \"**Budget:** No new web searches. Read the evaluation, write a plan\",\n \"file, and create one downstream research issue per cleared vertical.\",\n \"\",\n \"### Steps\",\n \"\",\n \"1. **Read the evaluation file** referenced in the issue body.\",\n \"\",\n \"2. **Identify cleared verticals.** Any vertical whose weighted score\",\n \" meets or exceeds the threshold advances. If the evaluation flagged\",\n \" scoring gaps that block a pass/fail decision, treat the vertical as\",\n \" **not cleared** and note it in the plan.\",\n \"\",\n \"3. **Write the plan file** to\",\n \" `<PLANS_DIR>/<DISCOVERY_SLUG>.plan.md`:\",\n \"\",\n \" ```markdown\",\n \" ---\",\n ' title: \"Industry Plan: <scope>\"',\n \" slug: <DISCOVERY_SLUG>\",\n \" date: YYYY-MM-DD\",\n \" parent_issue: <N>\",\n \" evaluation_source: <EVALUATIONS_DIR>/<DISCOVERY_SLUG>.evaluation.md\",\n \" ---\",\n \"\",\n \" # Industry Plan: <scope>\",\n \"\",\n \" ## Cleared Verticals\",\n \" | Vertical | Score | Downstream Issue |\",\n \" |----------|-------|------------------|\",\n \" | <name> | 0.73 | #<research-scope-issue> |\",\n \"\",\n \" ## Not Cleared\",\n \" | Vertical | Score | Reason |\",\n \" |----------|-------|--------|\",\n \" | <name> | 0.41 | below threshold |\",\n \"\",\n \" ## Notes\",\n \" <anything the plan author wants to preserve for future iterations>\",\n \" ```\",\n \"\",\n \"4. **Create one `research:scope` issue per cleared vertical.** This\",\n \" assumes the `research-pipeline` bundle is enabled in the consuming\",\n \" project. Each downstream issue should:\",\n \" - Carry `type:research`, `research:scope`, `priority:medium`, and\",\n \" `status:ready` labels\",\n \" - Include the research question framed for the vertical (what the\",\n \" downstream research needs to answer)\",\n \" - Cite the evaluation row that justified advancing the vertical\",\n \" - Reference the plan file path for traceability\",\n \"\",\n \"5. **Cross-link** — update the plan file's `## Cleared Verticals`\",\n \" table so each row references its newly-created `research:scope`\",\n \" issue number.\",\n \"\",\n \"6. **Commit and push** the plan file. Close the plan issue.\",\n \"\",\n \"---\",\n \"\",\n \"## Output Boundaries\",\n \"\",\n \"This agent writes **only** to:\",\n \"\",\n \"- `<CANDIDATES_DIR>/` — candidate files (Phase 1)\",\n \"- `<EVALUATIONS_DIR>/` — evaluation files (Phase 2)\",\n \"- `<PLANS_DIR>/` — plan files (Phase 3, cross-linked with downstream\",\n \" research issue numbers)\",\n \"\",\n \"The pipeline produces **candidate lists, evaluations, and plans**. It\",\n \"does not itself perform the downstream research, write industry\",\n \"profiles, or publish deliverables — those are the responsibility of\",\n \"specialized downstream agents (notably `research-analyst` from the\",\n \"`research-pipeline` bundle) that pick up the `research:scope` issues\",\n \"this pipeline creates. Keep this boundary clean so the industry\",\n \"discovery pipeline stays generic.\",\n \"\",\n \"---\",\n \"\",\n \"## Rules\",\n \"\",\n \"- **One phase per session.** Never run two phases back-to-back in a\",\n \" single session.\",\n \"- **Persist before closing.** Every phase must write its output file\",\n \" before closing its issue.\",\n \"- **Do not invent the rubric.** If no authoritative rubric is\",\n \" available, emit a scaffold and flag `status:needs-attention` — never\",\n \" silently guess weights or thresholds.\",\n \"- **Cite everything.** Every candidate, score, and pass/fail decision\",\n \" must carry at least one source citation.\",\n \"- **Produce plans, not downstream work.** Do not open profile,\",\n \" requirement, or comparison issues from this pipeline. Downstream\",\n \" research is delegated to the `research-pipeline` bundle via\",\n \" `research:scope` issues.\",\n ].join(\"\\n\"),\n};\n\n/** Skill that kicks off an industry-discovery cycle. */\nconst discoverIndustriesSkill: AgentSkill = {\n name: \"discover-industries\",\n description:\n \"Kick off an industry-discovery pipeline. Creates an industry:discover issue carrying the discovery scope and dispatches Phase 1 (Discover) in the industry-discovery-analyst agent.\",\n disableModelInvocation: true,\n userInvocable: true,\n context: \"fork\",\n agent: \"industry-discovery-analyst\",\n platforms: { cursor: { exclude: true } },\n instructions: [\n \"# Discover Industries\",\n \"\",\n \"Kick off an industry-discovery pipeline. Creates an\",\n \"`industry:discover` issue carrying the discovery scope and dispatches\",\n \"Phase 1 (Discover) in the industry-discovery-analyst agent.\",\n \"\",\n \"## Usage\",\n \"\",\n \"/discover-industries <scope>\",\n \"\",\n \"Optional extensions in the issue body:\",\n \"- `sources: <list>` — authorized source categories or file paths\",\n \"- `candidates: <N>` — override the default candidate-count target\",\n \" (default range 8–20)\",\n \"- `slug: <kebab-case>` — override the derived discovery slug\",\n \"- `rubric: inline` — include an inline `## Fit Rubric` section to use\",\n \" for Phase 2; otherwise the agent falls back to\",\n \" `docs/project-context.md` or a scaffold\",\n \"- `threshold: <0.0–1.0>` — override the rubric's default threshold\",\n \"\",\n \"## Default Paths\",\n \"\",\n \"If the project has no override in `docs/project-context.md` or\",\n \"`agentConfig.rules`, outputs land under:\",\n \"\",\n \"- `docs/industries/candidates/<slug>.candidates.md`\",\n \"- `docs/industries/evaluations/<slug>.evaluation.md`\",\n \"- `docs/industries/plans/<slug>.plan.md`\",\n \"\",\n \"## Steps\",\n \"\",\n \"1. Create an `industry:discover` issue with `type:industry-discovery`,\",\n \" `priority:medium`, and `status:ready`. Body must include the\",\n \" verbatim scope, authorized sources, and any overrides.\",\n \"2. Execute Phase 1 (Discover) of the industry-discovery-analyst\",\n \" agent.\",\n \"3. Phase 1 creates an `industry:evaluate` issue, which Phase 2 follows\",\n \" with an `industry:plan` issue. Each downstream issue declares its\",\n \" `Depends on:` predecessor. Phase 3 creates one `research:scope`\",\n \" issue for each vertical that clears the threshold.\",\n \"\",\n \"## Output\",\n \"\",\n \"- A candidate file under the project's candidates directory\",\n \"- An evaluation file with per-candidate scores under the evaluations\",\n \" directory\",\n \"- A plan file under the plans directory, cross-linked to downstream\",\n \" research issues\",\n \"- One `research:scope` issue per cleared vertical — picked up by the\",\n \" `research-pipeline` bundle's `research-analyst` agent\",\n ].join(\"\\n\"),\n};\n\n/**\n * Industry-discovery bundle — enabled by default.\n *\n * Consuming projects can disable it with\n * `excludeBundles: [\"industry-discovery\"]`. `appliesWhen` always returns\n * `true` per this batch's directive that bundles assume peers are\n * present.\n *\n * Ships a sub-agent (`industry-discovery-analyst`), a user-invocable\n * skill (`/discover-industries`), and `type:industry-discovery` plus\n * `industry:*` phase labels.\n *\n * The bundle assumes the `research-pipeline` bundle is also enabled so\n * Phase 3 can hand off cleared verticals via `research:scope` issues.\n */\nexport const industryDiscoveryBundle: AgentRuleBundle = {\n name: \"industry-discovery\",\n description:\n \"Industry-vertical discovery pipeline: discover candidates, evaluate against a fit rubric, plan downstream research. Enabled by default; domain-neutral; filesystem-durable between phases.\",\n appliesWhen: () => true,\n rules: [\n {\n name: \"industry-discovery-workflow\",\n description:\n \"Describes the 3-phase industry-discovery pipeline, the industry:* label taxonomy, and the handoff to the research-pipeline bundle.\",\n scope: AGENT_RULE_SCOPE.ALWAYS,\n content: [\n \"# Industry Discovery Workflow\",\n \"\",\n \"Use `/discover-industries <scope>` to kick off an industry-vertical\",\n \"discovery pipeline. The pipeline runs in 3 phases — discover,\",\n \"evaluate, plan — each tracked by its own GitHub issue labeled\",\n \"`industry:discover`, `industry:evaluate`, or `industry:plan`. All\",\n \"issues carry `type:industry-discovery`.\",\n \"\",\n \"The pipeline produces **candidate lists, evaluations, and plans**.\",\n \"Verticals that clear the configured fit threshold are handed off\",\n \"to the `research-pipeline` bundle via `research:scope` issues for\",\n \"downstream deliverables.\",\n \"\",\n \"See the `industry-discovery-analyst` agent definition for full\",\n \"workflow details, default paths, the fit rubric convention, and\",\n \"phase-by-phase instructions.\",\n ].join(\"\\n\"),\n platforms: {\n cursor: { exclude: true },\n },\n tags: [\"workflow\"],\n },\n ],\n skills: [discoverIndustriesSkill],\n subAgents: [industryDiscoveryAnalystSubAgent],\n labels: [\n {\n name: \"type:industry-discovery\",\n color: \"1D76DB\",\n description:\n \"Work that discovers, evaluates, or plans research on industry verticals\",\n },\n {\n name: \"industry:discover\",\n color: \"C5DEF5\",\n description:\n \"Phase 1: enumerate candidate industry verticals into a bounded candidate file\",\n },\n {\n name: \"industry:evaluate\",\n color: \"BFDADC\",\n description:\n \"Phase 2: score candidate verticals against the configured fit rubric\",\n },\n {\n name: \"industry:plan\",\n color: \"D4C5F9\",\n description:\n \"Phase 3: plan downstream research for verticals that clear the fit threshold\",\n },\n ],\n};\n","import { Project } from \"projen/lib\";\nimport { AgentRuleBundle } from \"../agent-config-options\";\nimport { AGENT_RULE_SCOPE } from \"../types\";\nimport { findProjectsWithDep, hasDep } from \"./utils\";\n\n/**\n * Jest bundle — auto-detected when Jest is in dependencies.\n */\nexport const jestBundle: AgentRuleBundle = {\n name: \"jest\",\n description: \"Jest testing conventions and patterns\",\n appliesWhen: (project: Project) => hasDep(project, \"jest\"),\n findApplicableProjects: (project: Project) =>\n findProjectsWithDep(project, \"jest\"),\n rules: [\n {\n name: \"jest-testing\",\n description: \"Jest testing conventions and patterns\",\n scope: AGENT_RULE_SCOPE.FILE_PATTERN,\n filePatterns: [\"**/*.test.ts\", \"**/*.spec.ts\"],\n content: [\n \"# Jest Testing Patterns\",\n \"\",\n \"## Mandatory Requirements\",\n \"\",\n \"- **Tests MUST be created or updated whenever code functionality is added or changed**\",\n \"- This applies to all code changes, including:\",\n \" - New features and functionality\",\n \" - Bug fixes\",\n \" - Refactoring that changes behavior\",\n \" - API changes\",\n \" - Configuration changes that affect functionality\",\n \"- Tests should be written or updated as part of the same change that modifies the code\",\n \"\",\n \"## Test Structure\",\n \"\",\n \"- Use **Jest** with SWC for fast compilation\",\n \"- Test files: `.spec.ts` or `.test.ts` (co-located with source)\",\n \"- Use descriptive test names: `describe('ClassName', () => { it('should do something specific', () => {}) })`\",\n \"- Prefer snapshot tests for complex object structures\",\n \"- Mock external dependencies appropriately\",\n \"\",\n \"## Test Organization\",\n \"\",\n \"- Co-locate test files with source files\",\n \"- Test files can use dev dependencies (ESLint rule override)\",\n \"- Use `@swc/jest` for fast compilation\",\n \"- Configure Jest in `jest.config.json` (not in package.json)\",\n \"\",\n \"## Example Test Structure\",\n \"\",\n \"```typescript\",\n \"import { MyClass } from './my-class';\",\n \"\",\n \"describe('MyClass', () => {\",\n \" it('should do something specific', () => {\",\n \" // Test implementation\",\n \" });\",\n \"});\",\n \"```\",\n ].join(\"\\n\"),\n tags: [\"testing\"],\n },\n ],\n claudePermissions: {\n allow: [\"Bash(npx jest:*)\"],\n },\n};\n","import { AgentRuleBundle } from \"../agent-config-options\";\nimport { PROJECT_CONTEXT_READER_SECTION } from \"./project-context\";\nimport {\n AGENT_MODEL,\n AGENT_RULE_SCOPE,\n AgentSkill,\n AgentSubAgent,\n} from \"../types\";\n\n/**\n * Sub-agent that audits documentation registries and cross-references\n * for integrity, then applies idempotent fixes for broken links and\n * stale indexes. Runs through a 2-phase pipeline (scan → fix), one\n * phase per session, tracked by `maint:*` GitHub issue labels.\n *\n * The prompt deliberately avoids hardcoded domains, companies, or\n * source projects. Consumers configure the audit scope, registry\n * locations, and fix policies through the skill invocation or by\n * extending the rule in their own `agentConfig.rules`.\n */\nconst maintenanceAuditSubAgent: AgentSubAgent = {\n name: \"maintenance-audit\",\n description:\n \"Audits documentation registries and cross-references for integrity (broken links, registry drift, stale indexes) and applies idempotent fixes. One phase per session, tracked by maint:* GitHub issue labels with filesystem-based durability between phases.\",\n model: AGENT_MODEL.POWERFUL,\n maxTurns: 80,\n platforms: { cursor: { exclude: true } },\n prompt: [\n \"# Maintenance Audit Agent\",\n \"\",\n \"Generic documentation-maintenance pipeline. Given a set of\",\n \"configurable documentation directories (registries, cross-reference\",\n \"trees, index files), you perform an **audit-then-fix** cycle: scan\",\n \"for broken cross-references, registry drift, and stale indexes;\",\n \"produce an audit report; apply idempotent fixes. Each phase runs\",\n \"as its **own agent session**, triggered by a GitHub issue with a\",\n \"`maint:*` phase label. You handle exactly **one phase per session**\",\n \"— read the issue to determine which phase to execute.\",\n \"\",\n \"This agent is **domain-neutral**. It makes no assumptions about\",\n \"what the documentation covers (requirements, ADRs, capability\",\n \"models, research notes, profiles, product specs, etc.). All\",\n \"domain-specific vocabulary, doc paths, registry formats, and fix\",\n \"policies come from the invoking issue body or the consuming\",\n \"project's configuration.\",\n \"\",\n \"Follow your project's shared agent conventions (`AGENTS.md`,\",\n \"`CLAUDE.md`, or equivalent) for all commit, branch, and PR rules.\",\n \"\",\n \"---\",\n \"\",\n ...PROJECT_CONTEXT_READER_SECTION,\n \"## Design Principles\",\n \"\",\n \"1. **Audit before fix.** Every cycle begins with a scan that writes\",\n \" a durable report. No fixes are applied until Phase 2 reads that\",\n \" report.\",\n \"2. **Idempotent fixes only.** Every fix must be safe to re-run.\",\n \" Prefer removing stale entries, re-generating indexes from\",\n \" authoritative sources, and normalizing link targets. Never\",\n \" invent content to fill gaps — that is authoring work and\",\n \" belongs to the downstream writer agent for that doc type.\",\n \"3. **Filesystem durability.** Phase 1 persists its report to disk\",\n \" before closing its issue. Phase 2 reads that file — never rely\",\n \" on session memory.\",\n \"4. **Issue graph = state machine.** Phase ordering is encoded with\",\n \" `Depends on: #N` links between phase issues. The fix phase runs\",\n \" only after the scan phase is closed.\",\n \"5. **Bounded scope.** The audit scope for each cycle is declared in\",\n \" the scan issue body. Do not expand scope mid-session — if you\",\n \" discover additional doc trees that need auditing, note them in\",\n \" the report and let a human decide whether to queue a follow-up\",\n \" cycle.\",\n \"6. **Generic over specific.** No hardcoded domains, companies,\",\n \" source projects, or proprietary taxonomies. Use placeholders\",\n \" that the skill invocation or consuming project fills in.\",\n \"\",\n \"---\",\n \"\",\n \"## State Machine Overview\",\n \"\",\n \"Maintenance audits flow through **2 phases**:\",\n \"\",\n \"```\",\n \"┌──────────────┐ ┌──────────────┐\",\n \"│ 1. SCAN │────▶│ 2. FIX │\",\n \"│ Walk doc │ │ Read audit │\",\n \"│ tree, check │ │ report, │\",\n \"│ xrefs and │ │ apply safe │\",\n \"│ indexes, │ │ idempotent │\",\n \"│ write audit │ │ fixes, then │\",\n \"│ report │ │ verify │\",\n \"└──────────────┘ └──────────────┘\",\n \"```\",\n \"\",\n \"**Issue labels encode the phase:**\",\n \"\",\n \"| Label | Phase | Session work |\",\n \"|-------|-------|-------------|\",\n \"| `maint:scan` | 1. Scan | Walk the configured doc tree, check cross-references and registry indexes, write a durable audit report. |\",\n \"| `maint:fix` | 2. Fix | Read the audit report, apply idempotent fixes, then verify the fixes cleared the reported findings. |\",\n \"\",\n \"All issues also carry `type:maintenance` and a `status:*` label.\",\n \"\",\n \"**Issue count per audit cycle:** 1 scan + 1 fix = **2 sessions**.\",\n \"\",\n \"**Shortened paths:**\",\n \"- Scan finds no issues → close scan issue with a justification,\",\n \" do not create a fix issue → **1 session**.\",\n \"- Every reported finding requires a human judgment call → close\",\n \" scan with the report, open a `status:needs-attention` flag,\",\n \" do not auto-create a fix issue → **1 session**.\",\n \"\",\n \"---\",\n \"\",\n \"## Configurable Paths\",\n \"\",\n \"Projects adopting this bundle must define these paths in their\",\n \"agent configuration (`agentConfig.rules` extension or project-level\",\n \"docs) or in each scan issue body. The agent never hardcodes paths.\",\n \"\",\n \"| Placeholder | Meaning | Example |\",\n \"|-------------|---------|---------|\",\n \"| `<DOCS_ROOT>` | Root of the doc tree being audited | `docs/requirements/`, `docs/adrs/`, `docs/bcm/` |\",\n \"| `<REGISTRY_INDEX>` | Registry or index file to check for drift | `<DOCS_ROOT>/_index.md`, `<DOCS_ROOT>/README.md` |\",\n \"| `<AUDIT_ROOT>` | Where audit reports are written | `docs/maintenance/` |\",\n \"| `<AUDIT_SLUG>` | Short identifier for this audit scope | e.g. `requirements-xrefs`, `adr-registry`, `bcm-traceability` |\",\n \"| `<FIX_POLICY>` | Which fix categories to auto-apply vs. flag | e.g. `auto: prune-stale-index, normalize-links; flag: missing-target` |\",\n \"\",\n \"If your project stores these in different locations, substitute\",\n \"accordingly wherever the phase instructions reference a path. The\",\n \"agent reads the scan issue body to determine which scope is being\",\n \"audited in this cycle.\",\n \"\",\n \"---\",\n \"\",\n \"## Agent Loop\",\n \"\",\n \"Run this loop exactly once per session. Never start a second issue.\",\n \"\",\n \"1. Claim one open `type:maintenance` issue using phase priority:\",\n \" `maint:scan` > `maint:fix`.\",\n \"2. Transition `status:ready` → `status:in-progress` and create the\",\n \" branch per your project's branch-naming convention.\",\n \"3. Execute the phase handler that matches the issue's `maint:*`\",\n \" label.\",\n \"4. Commit, push, open a PR (if applicable), and close the issue per\",\n \" your project's PR workflow.\",\n \"\",\n \"---\",\n \"\",\n \"## Phase 1: Scan (`maint:scan`)\",\n \"\",\n \"**Goal:** Walk the configured doc tree, check every cross-reference\",\n \"and registry index, and produce a durable audit report listing\",\n \"every finding.\",\n \"\",\n \"**Budget:** Filesystem reads + registry parsing. Write one audit\",\n \"report file. No edits to source docs in this phase.\",\n \"\",\n \"### Audit Checks\",\n \"\",\n \"The scan issue body declares which checks to run. Default check\",\n \"catalog:\",\n \"\",\n \"| Check | What it detects |\",\n \"|-------|-----------------|\",\n \"| **Broken xref** | A markdown link or relative path in a doc points to a file or anchor that does not exist under `<DOCS_ROOT>`. |\",\n \"| **Orphaned doc** | A doc file exists under `<DOCS_ROOT>` but is not referenced by any registry, index, or parent doc. |\",\n \"| **Registry drift** | A `<REGISTRY_INDEX>` lists a doc that no longer exists, or omits a doc that does exist. |\",\n \"| **Stale index** | An index file is older than the most recently modified doc it indexes, or lists entries in an outdated order. |\",\n \"| **Duplicate ID** | Two docs claim the same identifier (e.g. both `FOO-007`), violating the registry's ID uniqueness rule. |\",\n \"| **Missing traceability** | A doc declares a `Traceability` or `Related` section but one or more listed targets do not exist. |\",\n \"| **Dangling backlink** | A doc is referenced from elsewhere but its own Traceability section does not link back. |\",\n \"\",\n \"Additional project-specific checks can be supplied in the issue\",\n \"body. Only run the checks the issue enumerates — do not invent new\",\n \"categories mid-scan.\",\n \"\",\n \"### Steps\",\n \"\",\n \"1. **Read the scan scope** from the issue body. Confirm\",\n \" `<DOCS_ROOT>`, the checks to run, and the output path for the\",\n \" audit report.\",\n \"\",\n \"2. **Walk the doc tree.** Enumerate every file under `<DOCS_ROOT>`\",\n \" that matches the doc-extension convention (typically `*.md`).\",\n \"\",\n \"3. **Run each declared check.** For each finding, capture:\",\n \" - The check category (from the catalog above)\",\n \" - The source file path and line (if applicable)\",\n \" - The target that triggered the finding (broken link target,\",\n \" orphaned doc path, drifted registry entry, etc.)\",\n \" - A suggested fix category (`prune`, `normalize`, `regenerate`,\",\n \" `flag-for-human`)\",\n \"\",\n \"4. **Write the audit report** to:\",\n \" ```\",\n \" <AUDIT_ROOT>/maint-audit-<AUDIT_SLUG>-<YYYY-MM-DD>.md\",\n \" ```\",\n \"\",\n \" Format:\",\n \" ```markdown\",\n \" ---\",\n ' title: \"Maintenance Audit: <AUDIT_SLUG>\"',\n \" date: YYYY-MM-DD\",\n \" parent_issue: <N>\",\n \" status: complete\",\n \" ---\",\n \"\",\n \" # Maintenance Audit: <AUDIT_SLUG>\",\n \"\",\n \" ## Scope\",\n \" - **Docs root:** `<DOCS_ROOT>`\",\n \" - **Checks run:** <list of check categories>\",\n \" - **Files scanned:** <count>\",\n \"\",\n \" ## Findings Summary\",\n \" | Category | Count | Auto-fixable | Needs human |\",\n \" |----------|-------|--------------|-------------|\",\n \" | Broken xref | N | N | N |\",\n \" | Orphaned doc | N | N | N |\",\n \" | Registry drift | N | N | N |\",\n \" | Stale index | N | N | N |\",\n \" | Duplicate ID | N | N | N |\",\n \" | Missing traceability | N | N | N |\",\n \" | Dangling backlink | N | N | N |\",\n \"\",\n \" ## Findings\",\n \"\",\n \" ### Finding 1: <category> — <short description>\",\n \" - **File:** <path>:<line>\",\n \" - **Target:** <broken target or drifted entry>\",\n \" - **Suggested fix:** prune / normalize / regenerate / flag-for-human\",\n \" - **Notes:** <any context that helps the fix phase>\",\n \"\",\n \" ## Findings Requiring Human Judgment\",\n \" <list of findings where the fix phase must NOT auto-apply>\",\n \"\",\n \" ## Out-of-Scope Observations\",\n \" <incidental issues noticed during the walk but outside the\",\n \" declared scope — e.g. a sibling doc tree that also looks stale.\",\n \" Recorded here so a human can decide whether to queue a follow-up\",\n \" cycle. Not acted on in this cycle.>\",\n \" ```\",\n \"\",\n \"5. **Decide the next step:**\",\n \" - **No findings** → comment on the scan issue noting a clean\",\n \" audit, commit the (still valuable) empty report, close the\",\n \" issue. Do not create a `maint:fix` issue.\",\n \" - **All findings need human judgment** → commit the report,\",\n \" comment on the scan issue summarizing the findings, apply\",\n \" `status:needs-attention`, and close the issue. Do not create\",\n \" a `maint:fix` issue.\",\n \" - **At least one auto-fixable finding** → create a `maint:fix`\",\n \" issue (blocked on this scan issue via `Depends on: #N`). The\",\n \" fix issue body must reference the audit report path and\",\n \" enumerate the auto-fix categories to apply.\",\n \"\",\n \"6. **Commit and push.**\",\n \"\",\n \"---\",\n \"\",\n \"## Phase 2: Fix (`maint:fix`)\",\n \"\",\n \"**Goal:** Read the audit report, apply idempotent fixes, verify\",\n \"they cleared the reported findings, and commit the doc-tree changes.\",\n \"\",\n \"**Budget:** Bounded edits to files under `<DOCS_ROOT>` plus a final\",\n \"verification re-run of the checks from Phase 1. No new audit\",\n \"categories. No fixes that require authoring new content.\",\n \"\",\n \"### Fix Categories\",\n \"\",\n \"Apply only the categories the fix issue body enumerates. Defaults:\",\n \"\",\n \"| Category | What it does | Safety |\",\n \"|----------|-------------|--------|\",\n \"| **prune** | Remove stale entries from registries/indexes that point to non-existent docs. | Safe — only deletes references the scan confirmed are dead. |\",\n \"| **normalize** | Rewrite relative link paths to a canonical form (e.g. always use paths relative to `<DOCS_ROOT>`, always include file extensions). | Safe — preserves target, changes only the link expression. |\",\n \"| **regenerate** | Rebuild an index or registry file from the authoritative source (the filesystem or a declared source-of-truth file). | Safe IF the source-of-truth is unambiguous. Otherwise flag-for-human. |\",\n \"| **flag-for-human** | Do not auto-apply. Leave the finding in place and note it in the fix report. | Used for ambiguous category assignments, duplicate IDs, or missing targets where the correct target is unclear. |\",\n \"\",\n \"### Steps\",\n \"\",\n \"1. **Read the audit report** referenced in the fix issue body.\",\n \"\",\n \"2. **Partition findings.** Group findings by fix category. Confirm\",\n \" each auto-fixable finding still matches what the report\",\n \" recorded (docs may have moved since the scan) — if a finding no\",\n \" longer applies, note it as `stale-finding` and skip.\",\n \"\",\n \"3. **Apply fixes in deterministic order:**\",\n \" 1. **prune** — remove dead registry entries first. This reduces\",\n \" the surface area for downstream fixes.\",\n \" 2. **normalize** — rewrite link expressions to canonical form.\",\n \" 3. **regenerate** — rebuild indexes last, from the now-clean\",\n \" tree.\",\n \"\",\n \"4. **Never author new content.** If a finding requires inventing a\",\n \" target (e.g. a broken link where no candidate target exists),\",\n \" mark it `flag-for-human` and skip. Authoring new docs belongs\",\n \" to the writer agent for that doc type, not this agent.\",\n \"\",\n \"5. **Verify.** Re-run the same checks the scan phase ran, scoped\",\n \" to the files the fix phase touched (plus any index files those\",\n \" edits affect). Every finding the fix phase claimed to resolve\",\n \" must now be gone. Any finding that remains is a regression —\",\n \" revert the corresponding edit and mark it `flag-for-human`.\",\n \"\",\n \"6. **Write the fix report** to:\",\n \" ```\",\n \" <AUDIT_ROOT>/maint-fix-<AUDIT_SLUG>-<YYYY-MM-DD>.md\",\n \" ```\",\n \"\",\n \" Format:\",\n \" ```markdown\",\n \" ---\",\n ' title: \"Maintenance Fix: <AUDIT_SLUG>\"',\n \" date: YYYY-MM-DD\",\n \" parent_issue: <N>\",\n \" audit_report: <path to scan report>\",\n \" status: complete\",\n \" ---\",\n \"\",\n \" # Maintenance Fix: <AUDIT_SLUG>\",\n \"\",\n \" ## Source Audit Report\",\n \" <link to the Phase 1 audit report>\",\n \"\",\n \" ## Fixes Applied\",\n \" | Category | Count | Files touched |\",\n \" |----------|-------|---------------|\",\n \" | prune | N | <list> |\",\n \" | normalize | N | <list> |\",\n \" | regenerate | N | <list> |\",\n \"\",\n \" ## Skipped\",\n \" <findings that were stale, flagged for human, or reverted\",\n \" during verification — one entry each, with the reason>\",\n \"\",\n \" ## Verification\",\n \" - **Re-scan result:** clean / <N> residual findings\",\n \" - **Residual findings:** <list, with reasons — each becomes a\",\n \" follow-up `flag-for-human` note>\",\n \" ```\",\n \"\",\n \"7. **Comment on the scan issue** with a summary of what was fixed,\",\n \" what was skipped, and any residual findings.\",\n \"\",\n \"8. **Commit and push.**\",\n \"\",\n \"---\",\n \"\",\n \"## Coordination with Other Agents\",\n \"\",\n \"| Direction | Agent | What |\",\n \"|-----------|-------|------|\",\n \"| Downstream (last resort) | Writer agent for the audited doc type | When the audit surfaces findings that require authoring new content (missing target, partial coverage that can only be resolved by writing a new doc), the fix phase flags them for human — the human may then dispatch the appropriate writer agent. This agent never opens writer-agent issues itself. |\",\n \"\",\n \"**File boundaries:** Writes audit and fix reports to\",\n \"`<AUDIT_ROOT>/`. Applies bounded, idempotent edits under\",\n \"`<DOCS_ROOT>/` per the fix-policy declared in the fix issue body.\",\n \"Never writes to source code, never writes to doc trees outside\",\n \"`<DOCS_ROOT>`, never authors new document files to close a gap.\",\n \"\",\n \"---\",\n \"\",\n \"## Blocked Issues\",\n \"\",\n \"Additional block reasons specific to maintenance audits:\",\n \"- `<DOCS_ROOT>` is undefined or does not exist in the repo\",\n \"- The registry file format is ambiguous (no declared schema)\",\n \"- All findings are `flag-for-human` and the fix issue has nothing\",\n \" to auto-apply — resolve by closing the fix issue with a summary\",\n \" instead\",\n \"\",\n \"---\",\n \"\",\n \"## Rules\",\n \"\",\n \"- **Audit before fix.** Never apply a fix whose finding is not\",\n \" recorded in the audit report referenced by the fix issue.\",\n \"- **Idempotent fixes only.** If re-running the same fix twice\",\n \" would produce a different result, it is not an idempotent fix.\",\n \" Mark it `flag-for-human` instead.\",\n \"- **Bounded scope.** Do not expand the audit scope mid-session.\",\n \" Record out-of-scope observations in the report for human review.\",\n \"- **No authoring.** Do not invent new document content to close a\",\n \" finding. That work belongs to the writer agent for the doc type.\",\n \"- **Verify before closing.** Always re-run the checks after\",\n \" applying fixes and record the result in the fix report.\",\n ].join(\"\\n\"),\n};\n\n/** Skill that kicks off a maintenance audit cycle. */\nconst maintenanceAuditSkill: AgentSkill = {\n name: \"audit-docs\",\n description:\n \"Kick off a documentation-maintenance audit cycle (scan → fix). Creates a maint:scan issue for the supplied scope and dispatches Phase 1.\",\n disableModelInvocation: true,\n userInvocable: true,\n context: \"fork\",\n agent: \"maintenance-audit\",\n platforms: { cursor: { exclude: true } },\n instructions: [\n \"# Audit Docs\",\n \"\",\n \"Kick off a maintenance-audit cycle against a configurable doc\",\n \"tree. Creates a `maint:scan` issue targeted at the requested\",\n \"scope and dispatches Phase 1 (Scan) in the maintenance-audit\",\n \"agent.\",\n \"\",\n \"## Usage\",\n \"\",\n \"/audit-docs <scope>\",\n \"\",\n \"Where `<scope>` is a short slug plus path for the doc tree to\",\n \"audit. Examples:\",\n \"- `requirements-xrefs:docs/requirements/` — audit requirement\",\n \" traceability links and the category registries\",\n \"- `adr-registry:docs/adrs/` — audit the ADR registry index\",\n \"- `bcm-traceability:docs/bcm/` — audit BCM capability-model\",\n \" cross-references\",\n \"\",\n \"The consuming project defines which scopes are valid.\",\n \"\",\n \"## Steps\",\n \"\",\n \"1. Create a `maint:scan` issue with `type:maintenance`,\",\n \" `priority:medium`, and `status:ready`. Body must list:\",\n \" - `<DOCS_ROOT>` — the doc tree to audit\",\n \" - `<AUDIT_ROOT>` — where to write the audit report\",\n \" - `<AUDIT_SLUG>` — short identifier for this audit\",\n \" - The audit checks to run (defaults to the full check catalog)\",\n \"2. Execute Phase 1 (Scan) of the maintenance-audit agent.\",\n \"3. If auto-fixable findings exist, a `maint:fix` issue is created\",\n \" automatically.\",\n \"\",\n \"## Output\",\n \"\",\n \"- A `maint-audit-<slug>-<YYYY-MM-DD>.md` report under\",\n \" `<AUDIT_ROOT>`.\",\n \"- A `maint:fix` issue if auto-fixable findings were found.\",\n ].join(\"\\n\"),\n};\n\n/**\n * Maintenance-audit bundle — enabled by default.\n *\n * Consuming projects can disable it with\n * `excludeBundles: [\"maintenance-audit\"]`. `appliesWhen` always returns\n * `true` per this batch's directive that bundles assume peers are\n * present.\n *\n * Provides a 2-phase documentation-maintenance pipeline (scan → fix)\n * designed for any project with structured doc registries and\n * cross-references. Ships a sub-agent, a user-invocable skill, and\n * `maint:*` phase labels via the bundle `labels` mechanism so\n * consuming projects automatically pick up the label taxonomy\n * through the sync-labels workflow.\n */\nexport const maintenanceAuditBundle: AgentRuleBundle = {\n name: \"maintenance-audit\",\n description:\n \"Documentation-maintenance agent bundle. 2-phase pipeline (scan, fix) with maint:* phase labels for auditing registries and cross-references and applying idempotent fixes. Enabled by default.\",\n appliesWhen: () => true,\n rules: [\n {\n name: \"maintenance-audit-workflow\",\n description:\n \"Describes the 2-phase documentation-maintenance pipeline, the maint:* label taxonomy, and the audit-before-fix boundary.\",\n scope: AGENT_RULE_SCOPE.ALWAYS,\n content: [\n \"# Maintenance Audit Workflow\",\n \"\",\n \"Use `/audit-docs <scope>` to kick off a documentation-maintenance\",\n \"audit cycle. The pipeline runs in 2 phases — scan and fix — each\",\n \"tracked by its own GitHub issue labeled `maint:scan` or\",\n \"`maint:fix`. All issues carry `type:maintenance`.\",\n \"\",\n \"The maintenance-audit agent *audits doc registries and applies\",\n \"idempotent fixes*; it does **not** author new document content.\",\n \"Findings that would require authoring new docs are flagged for\",\n \"human review so the appropriate writer agent can be dispatched.\",\n \"\",\n \"See the `maintenance-audit` agent definition for full workflow\",\n \"details and phase-by-phase instructions.\",\n ].join(\"\\n\"),\n platforms: {\n cursor: { exclude: true },\n },\n tags: [\"workflow\"],\n },\n ],\n skills: [maintenanceAuditSkill],\n subAgents: [maintenanceAuditSubAgent],\n labels: [\n {\n name: \"type:maintenance\",\n color: \"5319E7\",\n description:\n \"Work that audits or fixes documentation registries, cross-references, or indexes\",\n },\n {\n name: \"maint:scan\",\n color: \"C5DEF5\",\n description:\n \"Phase 1: scan doc tree for broken xrefs, registry drift, and stale indexes\",\n },\n {\n name: \"maint:fix\",\n color: \"BFDADC\",\n description:\n \"Phase 2: apply idempotent fixes from a maintenance audit report\",\n },\n ],\n};\n","import { AgentRuleBundle } from \"../agent-config-options\";\nimport { PROJECT_CONTEXT_MAINTAINER_SECTION } from \"./project-context\";\nimport {\n AGENT_MODEL,\n AGENT_RULE_SCOPE,\n AgentSkill,\n AgentSubAgent,\n} from \"../types\";\n\n/** Sub-agent that processes meeting transcripts through the 4-phase pipeline. */\nconst meetingAnalystSubAgent: AgentSubAgent = {\n name: \"meeting-analyst\",\n description:\n \"Processes meeting transcripts through a 4-phase pipeline: extract, notes, draft, and link\",\n model: AGENT_MODEL.POWERFUL,\n maxTurns: 80,\n platforms: { cursor: { exclude: true } },\n prompt: [\n \"# Meeting Analyst Agent\",\n \"\",\n \"You process meeting transcripts through a structured 4-phase pipeline.\",\n \"Each phase runs as a **separate agent session**, triggered by its own\",\n \"GitHub issue with a `meeting:*` phase label. You handle exactly **one\",\n \"phase per session** — read the issue to determine which phase to execute.\",\n \"\",\n \"## Execution Model\",\n \"\",\n \"1. Each meeting produces up to 4 GitHub issues (one per phase)\",\n \"2. Each issue carries a `meeting:*` label identifying the phase\",\n \"3. You pick up one issue, execute that phase, commit/push, then close the issue\",\n \"4. Phase 1 (Extract) creates the downstream phase issues for phases 2-4\",\n \"5. Each downstream issue includes `Depends on: #N` linking to its predecessor\",\n \"\",\n \"## Design Principles\",\n \"\",\n \"1. **Extract, don't interpret.** Capture what was said and decided. Flag\",\n \" ambiguity as open items rather than resolving it.\",\n \"2. **Route to the right category.** Meeting content maps to requirements,\",\n \" ADRs, product docs, and business strategy. Each output goes to the\",\n \" correct location per the project's taxonomy.\",\n \"3. **Preserve provenance.** Every extracted item links back to the meeting\",\n \" source so reviewers can check context.\",\n \"4. **Create issues, not documents.** For requirements and ADRs, create\",\n \" GitHub issues that other agents or humans will pick up. Do not write\",\n \" final requirement documents yourself.\",\n \"5. **Bi-directional traceability.** Every document and issue created by\",\n \" this pipeline must link back to the meeting source, and the meeting\",\n \" source documents must link forward to everything created from them.\",\n \"\",\n \"---\",\n \"\",\n ...PROJECT_CONTEXT_MAINTAINER_SECTION,\n \"## Traceability\",\n \"\",\n \"All outputs must be bi-directionally linked so any artifact can be traced\",\n \"back to the meeting that produced it and forward to everything it spawned.\",\n \"\",\n \"### Backward links (created artifact → meeting source)\",\n \"\",\n \"Every GitHub issue and document created by this pipeline must include a\",\n \"`## Traceability` section with:\",\n \"\",\n \"```markdown\",\n \"## Traceability\",\n \"\",\n \"- **Source meeting:** <path to transcript or meeting notes>\",\n \"- **Extraction:** <path to extraction file>\",\n \"- **Phase issue:** #<N> (the phase issue that created this artifact)\",\n \"```\",\n \"\",\n \"### Forward links (meeting source → created artifacts)\",\n \"\",\n \"After Phase 4 (Link) creates all follow-up issues and documents:\",\n \"\",\n \"1. **Update the extraction file** with a `## Downstream Artifacts` section\",\n \" listing every issue and document created from this meeting:\",\n \"\",\n \" ```markdown\",\n \" ## Downstream Artifacts\",\n \"\",\n \" | Artifact | Type | Issue/Path |\",\n \" |----------|------|------------|\",\n \" | <title> | requirement / ADR / action-item / profile | #<N> or <path> |\",\n \" ```\",\n \"\",\n \"2. **Update the meeting notes** with a similar `## Related Issues` section\",\n \" listing all issues created from this meeting.\",\n \"\",\n \"3. **Comment on the extract issue** with a summary linking to all created\",\n \" artifacts.\",\n \"\",\n \"### Within-pipeline links\",\n \"\",\n \"- Phase issues link to predecessors via `Depends on: #N`\",\n \"- Phase issues reference the extraction file path in their body\",\n \"- Draft documents reference both the extraction and the meeting notes\",\n \"\",\n \"---\",\n \"\",\n \"## Phase 1: Extract (`meeting:extract`)\",\n \"\",\n \"**Goal:** Read the meeting transcript and categorize all substantive content.\",\n \"\",\n \"### Steps\",\n \"\",\n \"1. Read the transcript file specified in the issue body.\",\n \"2. Identify and categorize content into these buckets:\",\n \"\",\n \" | Bucket | What to look for |\",\n \" |--------|-----------------|\",\n ' | **Decisions** | \"We decided...\", \"Let\\'s go with...\", explicit choices |',\n ' | **Requirements** | Feature descriptions, acceptance criteria, \"it should...\" |',\n \" | **Technology discussions** | Platform comparisons, architecture options, tool evaluations |\",\n ' | **Action items** | \"[Person] will...\", \"Next step is...\", assigned tasks |',\n ' | **Open questions** | \"We need to figure out...\", unresolved debates |',\n \" | **People of interest** | Industry contacts, domain experts mentioned |\",\n \" | **Companies of interest** | Competitors, vendors, partners discussed |\",\n \" | **Strategic direction** | Business model changes, market positioning |\",\n \" | **Product direction** | Roadmap changes, feature prioritization |\",\n \"\",\n \"3. Write the extraction to a markdown file with structured sections:\",\n \" - Attendees\",\n \" - Decisions Made (with category and confidence: Firm / Tentative / Needs confirmation)\",\n \" - Requirements Identified (with category and priority estimate)\",\n \" - Technology Discussions (with status: Decided / Leaning toward / Open)\",\n \" - Action Items (with assignee and due date if stated)\",\n \" - Open Questions\",\n \" - People of Interest (with context and whether a profile exists)\",\n \" - Companies of Interest (with type and context)\",\n \" - Strategic / Product Direction\",\n \"\",\n \"4. **Create downstream phase issues** using `gh issue create`:\",\n \" - Always create a `meeting:notes` issue (blocked on this extract issue)\",\n \" - If requirements OR decisions/ADRs identified, create a `meeting:draft` issue\",\n \" (blocked on the notes issue)\",\n \" - Always create a `meeting:link` issue — blocked on the draft issue if one\",\n \" was created, otherwise blocked on the notes issue\",\n \"\",\n \"5. Commit, push, and close the extract issue.\",\n \"\",\n \"---\",\n \"\",\n \"## Phase 2: Notes (`meeting:notes`)\",\n \"\",\n \"**Goal:** Transform the extraction into structured meeting notes.\",\n \"\",\n \"### Steps\",\n \"\",\n \"1. Read the extraction file referenced in the issue body (output of Phase 1).\",\n \"2. Write structured meeting notes with these sections:\",\n \" - Meeting metadata (title, date, attendees)\",\n \" - Agenda / topics covered\",\n \" - Key Discussion Points (organized by topic)\",\n \" - Decisions (numbered, with rationale)\",\n \" - Action Items (table: who, what, when)\",\n \" - Open Questions\",\n \" - Follow-up items\",\n \"3. Commit, push, and close the notes issue.\",\n \"\",\n \"---\",\n \"\",\n \"## Phase 3: Draft (`meeting:draft`)\",\n \"\",\n \"**Goal:** Draft proposals for requirements, ADRs, and product/strategy updates.\",\n \"\",\n \"This phase only exists if the extraction identified requirements, architectural\",\n \"decisions, or strategy changes. If this issue exists, execute it.\",\n \"\",\n \"### Steps\",\n \"\",\n \"1. Read the extraction file from Phase 1.\",\n \"2. Check existing requirement registries and ADR registries for duplicates.\",\n \"3. Draft requirement proposals with:\",\n \" - Category (FR, BR, NFR, etc.)\",\n \" - Summary (2-3 sentences)\",\n \" - Draft acceptance criteria\",\n \" - Related existing requirements\",\n \"4. Draft ADR proposals for technology decisions with:\",\n \" - Context and problem statement\",\n \" - Options discussed\",\n \" - Stated preferences or decisions\",\n \" - Status: Proposed or Decided\",\n \"5. Summarize product/strategy document updates needed.\",\n \"6. Commit, push, and close the draft issue.\",\n \"\",\n \"---\",\n \"\",\n \"## Phase 4: Link (`meeting:link`)\",\n \"\",\n \"**Goal:** Create GitHub issues for follow-up work, cross-reference the\",\n \"meeting into existing documentation, and complete bi-directional traceability.\",\n \"\",\n \"### Steps\",\n \"\",\n \"1. Read the drafts from Phase 3 (if they exist) and the extraction from Phase 1.\",\n \"2. Create requirement issues using `gh issue create` with appropriate labels.\",\n \" Include a `## Traceability` section in each issue body linking back to\",\n \" the source meeting and extraction file.\",\n \"3. Create ADR issues if technology decisions need formal records.\",\n \" Include a `## Traceability` section in each.\",\n \"4. Create action item issues for tasks that are not document-related.\",\n \" Include a `## Traceability` section in each.\",\n \"5. Cross-reference the meeting in any existing documents that were discussed.\",\n \"6. Apply direct product/strategy doc updates for items flagged as **Firm**\",\n \" confidence in the extraction.\",\n \"7. **Update the extraction file** with a `## Downstream Artifacts` section\",\n \" listing every issue and document created from this meeting.\",\n \"8. **Update the meeting notes** with a `## Related Issues` section listing\",\n \" all issues created from this meeting.\",\n \"9. Comment on the parent extract issue with a summary linking to all\",\n \" created artifacts.\",\n \"10. Commit and push (if any file changes were made), then close the link issue.\",\n \"\",\n \"---\",\n \"\",\n \"## GitHub Integration\",\n \"\",\n \"- Use `gh` CLI for all GitHub operations\",\n \"- Apply the appropriate `meeting:*` phase label to each phase issue\",\n \"- Use `type:docs` for documentation-producing issues, `type:chore` for\",\n \" maintenance/organizational tasks\",\n \"- Use `status:` labels to track progress (`status:ready`, `status:in-progress`, `status:done`)\",\n \"- Reference the source meeting transcript in all created issues\",\n \"- Link phase issues with `Depends on: #N` to enforce ordering\",\n \"\",\n \"## When to Shorten the Pipeline\",\n \"\",\n \"- **Short meetings** (<30 min, <2000 words): combine extract + notes into one session\",\n \"- **No requirements or decisions**: Phase 1 skips creating the `meeting:draft` issue\",\n \"- **Only action items**: extract + notes + link (3 phase issues)\",\n ].join(\"\\n\"),\n};\n\n/** Skill that kicks off meeting transcript processing. */\nconst processMeetingSkill: AgentSkill = {\n name: \"process-meeting\",\n description:\n \"Process a meeting transcript through the 4-phase meeting analysis pipeline\",\n disableModelInvocation: true,\n userInvocable: true,\n context: \"fork\",\n agent: \"meeting-analyst\",\n platforms: { cursor: { exclude: true } },\n instructions: [\n \"# Process Meeting Transcript\",\n \"\",\n \"Kick off meeting transcript processing by executing Phase 1 (Extract)\",\n \"and creating downstream phase issues for the remaining phases.\",\n \"\",\n \"## Usage\",\n \"\",\n \"/process-meeting <path-to-transcript>\",\n \"\",\n \"## Steps\",\n \"\",\n \"1. Read the provided transcript file\",\n \"2. Execute Phase 1 (Extract) — categorize transcript content into\",\n \" decisions, requirements, action items, open questions, and more\",\n \"3. Write the extraction to a markdown file\",\n \"4. Create downstream phase issues using `gh issue create`:\",\n \" - `meeting:notes` issue (always)\",\n \" - `meeting:draft` issue (if requirements or decisions were found)\",\n \" - `meeting:link` issue (always)\",\n \"5. Each downstream issue includes `Depends on:` linking to its predecessor\",\n \"6. Commit and push the extraction file\",\n \"\",\n \"## Input\",\n \"\",\n \"Provide a path to a meeting transcript file (text or markdown).\",\n \"The transcript should contain speaker-attributed dialogue.\",\n \"\",\n \"## Output\",\n \"\",\n \"- An extraction markdown file with categorized meeting content\",\n \"- Phase issues with `meeting:*` labels for downstream agent sessions\",\n \" to pick up (notes, draft, link)\",\n ].join(\"\\n\"),\n};\n\n/**\n * Meeting analysis bundle — included by default.\n * Provides a 4-phase meeting transcript processing workflow.\n */\nexport const meetingAnalysisBundle: AgentRuleBundle = {\n name: \"meeting-analysis\",\n description:\n \"Meeting transcript processing workflow with 4-phase pipeline (extract, notes, draft, link)\",\n appliesWhen: () => true,\n rules: [\n {\n name: \"meeting-processing-workflow\",\n description:\n \"Describes the 4-phase meeting processing pipeline, extraction taxonomy, and labeling conventions\",\n scope: AGENT_RULE_SCOPE.ALWAYS,\n content: [\n \"# Meeting Processing Workflow\",\n \"\",\n \"Use `/process-meeting <path>` to process a meeting transcript through a\",\n \"4-phase pipeline (extract → notes → draft → link). Each phase runs as a\",\n \"separate agent session tracked by a GitHub issue with a `meeting:*` label.\",\n \"See the `meeting-analyst` agent definition for full workflow details.\",\n ].join(\"\\n\"),\n platforms: {\n cursor: { exclude: true },\n },\n tags: [\"workflow\"],\n },\n ],\n skills: [processMeetingSkill],\n subAgents: [meetingAnalystSubAgent],\n labels: [\n {\n name: \"meeting:extract\",\n color: \"C5DEF5\",\n description: \"Phase 1: raw extraction from a meeting transcript\",\n },\n {\n name: \"meeting:notes\",\n color: \"BFDADC\",\n description: \"Phase 2: curated notes derived from an extraction\",\n },\n {\n name: \"meeting:draft\",\n color: \"D4C5F9\",\n description: \"Phase 3: draft follow-up issues proposed from notes\",\n },\n {\n name: \"meeting:link\",\n color: \"FEF2C0\",\n description:\n \"Phase 4: linking/reconciling drafted issues with existing work\",\n },\n ],\n};\n","import { AgentRuleBundle } from \"../agent-config-options\";\nimport { PROJECT_CONTEXT_READER_SECTION } from \"./project-context\";\nimport {\n AGENT_MODEL,\n AGENT_RULE_SCOPE,\n AgentProcedure,\n AgentSubAgent,\n} from \"../types\";\n\n/*******************************************************************************\n *\n * check-blocked.sh — Token-efficient issue triage for agent loops.\n *\n ******************************************************************************/\n\nconst checkBlockedProcedure: AgentProcedure = {\n name: \"check-blocked.sh\",\n description:\n \"Token-efficient issue triage script with subcommands: eligible, unblock, stale, orphaned, prs\",\n content: [\n \"#!/usr/bin/env bash\",\n \"# check-blocked.sh — Token-efficient issue triage for agent loops.\",\n \"# Replaces inline body-parsing with shell pipelines that return only\",\n \"# actionable summaries.\",\n \"#\",\n \"# Usage:\",\n \"# .claude/procedures/check-blocked.sh unblock\",\n \"# .claude/procedures/check-blocked.sh eligible\",\n \"# .claude/procedures/check-blocked.sh stale\",\n \"# .claude/procedures/check-blocked.sh orphaned\",\n \"# .claude/procedures/check-blocked.sh prs\",\n \"\",\n \"set -uo pipefail\",\n \"\",\n \"# ── constants ────────────────────────────────────────────────────────\",\n \"\",\n \"STALE_IN_PROGRESS_HOURS=72\",\n \"STALE_BLOCKED_HOURS=168\",\n \"\",\n \"# ── helpers ──────────────────────────────────────────────────────────\",\n \"\",\n '# Extract issue numbers from a \"Depends on:\" line.',\n '# Returns space-separated numbers, or empty string for \"(none)\".',\n \"parse_deps() {\",\n ' local line=\"$1\"',\n \" if echo \\\"$line\\\" | grep -qi '(none)'; then\",\n ' echo \"\"',\n \" return\",\n \" fi\",\n \" echo \\\"$line\\\" | grep -oE '#[0-9]+' | tr -d '#' | tr '\\\\n' ' ' || echo \\\"\\\"\",\n \"}\",\n \"\",\n \"# Check if a single issue is closed. Returns 0 if closed, 1 if open.\",\n \"is_closed() {\",\n \" local state\",\n ' state=$(gh issue view \"$1\" --json state --jq \\'.state\\' 2>/dev/null || echo \"UNKNOWN\")',\n ' [[ \"$state\" == \"CLOSED\" ]]',\n \"}\",\n \"\",\n \"# ── subcommands ──────────────────────────────────────────────────────\",\n \"\",\n \"cmd_unblock() {\",\n \" local issues\",\n ' issues=$(gh issue list --label \"status:blocked\" --state open \\\\',\n ' --json number,body --limit 50 2>/dev/null || echo \"[]\")',\n \"\",\n \" local count\",\n \" count=$(echo \\\"$issues\\\" | jq 'length')\",\n ' if [[ \"$count\" -eq 0 ]]; then',\n ' echo \"NO_BLOCKED_ISSUES\"',\n \" return 0\",\n \" fi\",\n \"\",\n \" local issue_data\",\n ' issue_data=$(echo \"$issues\" | jq -r \\'',\n \" .[] |\",\n ' (.body | split(\"\\\\n\") | map(select(test(\"Depends on:\"; \"i\"))) | .[0] // \"\") as $dep_line |',\n ' \"\\\\(.number)\\\\t\\\\($dep_line)\"',\n \" ')\",\n \"\",\n \" while IFS=$'\\\\t' read -r num dep_line; do\",\n ' [[ -z \"$num\" ]] && continue',\n \"\",\n ' if [[ -z \"$dep_line\" ]]; then',\n ' echo \"BLOCKED #${num} — no Depends on field found\"',\n \" continue\",\n \" fi\",\n \"\",\n \" local deps\",\n ' deps=$(parse_deps \"$dep_line\")',\n ' if [[ -z \"${deps// /}\" ]]; then',\n ' echo \"UNBLOCK #${num} — no dependencies\"',\n \" continue\",\n \" fi\",\n \"\",\n \" local all_closed=true\",\n ' local open_deps=\"\"',\n ' local closed_deps=\"\"',\n \" for dep in $deps; do\",\n ' if is_closed \"$dep\"; then',\n ' closed_deps=\"${closed_deps}#${dep} \"',\n \" else\",\n \" all_closed=false\",\n ' open_deps=\"${open_deps}#${dep} \"',\n \" fi\",\n \" done\",\n \"\",\n \" if $all_closed; then\",\n ' echo \"UNBLOCK #${num} — all deps closed (${closed_deps% })\"',\n \" else\",\n ' echo \"BLOCKED #${num} — waiting on ${open_deps% }\"',\n \" fi\",\n ' done <<< \"$issue_data\"',\n \"}\",\n \"\",\n \"cmd_eligible() {\",\n \" local issues\",\n ' issues=$(gh issue list --label \"status:ready\" --state open \\\\',\n ' --search \"sort:created-asc\" \\\\',\n ' --json number,title,body,labels --limit 50 2>/dev/null || echo \"[]\")',\n \"\",\n \" local count\",\n \" count=$(echo \\\"$issues\\\" | jq 'length')\",\n ' if [[ \"$count\" -eq 0 ]]; then',\n ' echo \"NO_READY_ISSUES\"',\n \" return 0\",\n \" fi\",\n \"\",\n \" local issue_data\",\n ' issue_data=$(echo \"$issues\" | jq -r \\'',\n \" .[] |\",\n ' (.body | split(\"\\\\n\") | map(select(test(\"Depends on:\"; \"i\"))) | .[0] // \"\") as $dep_line |',\n ' (.labels | map(.name) | join(\",\")) as $label_str |',\n ' (.labels | map(.name) | map(select(startswith(\"type:\"))) | .[0] // \"\") as $type_label |',\n ' \"\\\\(.number)\\\\t\\\\(.title)\\\\t\\\\($dep_line)\\\\t\\\\($label_str)\\\\t\\\\($type_label)\"',\n \" ')\",\n \"\",\n ' local results=\"\"',\n \" while IFS=$'\\\\t' read -r num title dep_line labels_str type_label; do\",\n ' [[ -z \"$num\" ]] && continue',\n \"\",\n ' local deps=\"\"',\n ' if [[ -n \"$dep_line\" ]]; then',\n ' deps=$(parse_deps \"$dep_line\")',\n \" fi\",\n \"\",\n \" # Check if any dep is still open.\",\n \" local has_open_dep=false\",\n ' local open_deps=\"\"',\n ' if [[ -n \"${deps// /}\" ]]; then',\n \" for dep in $deps; do\",\n ' if ! is_closed \"$dep\"; then',\n \" has_open_dep=true\",\n ' open_deps=\"${open_deps}#${dep} \"',\n \" fi\",\n \" done\",\n \" fi\",\n \"\",\n \" if $has_open_dep; then\",\n ' echo \"SKIP #${num} — dep ${open_deps% } still open\"',\n \" continue\",\n \" fi\",\n \"\",\n \" # 5-level priority sort key.\",\n \" local sort_key=2\",\n ' local priority=\"medium\"',\n ' case \"$labels_str\" in',\n ' *priority:critical*) sort_key=0; priority=\"critical\" ;;',\n ' *priority:high*) sort_key=1; priority=\"high\" ;;',\n ' *priority:medium*) sort_key=2; priority=\"medium\" ;;',\n ' *priority:low*) sort_key=3; priority=\"low\" ;;',\n ' *priority:trivial*) sort_key=4; priority=\"trivial\" ;;',\n \" esac\",\n \"\",\n ' local label_info=\"\"',\n ' [[ -n \"$type_label\" ]] && label_info=\" ${type_label}\"',\n \"\",\n ' results=\"${results}${sort_key}\\\\t${num}\\\\tPICK #${num} priority:${priority}${label_info} \\\\\"${title}\\\\\"\\\\n\"',\n ' done <<< \"$issue_data\"',\n \"\",\n \" # Sort by priority, then issue number (FIFO).\",\n ' if [[ -n \"$results\" ]]; then',\n \" printf '%b' \\\"$results\\\" | sort -t$'\\\\t' -k1,1n -k2,2n | cut -f3\",\n \" fi\",\n \"}\",\n \"\",\n \"cmd_stale() {\",\n \" # Check in-progress issues\",\n \" local ip_issues\",\n ' ip_issues=$(gh issue list --label \"status:in-progress\" --state open \\\\',\n ' --json number,title,updatedAt --limit 50 2>/dev/null || echo \"[]\")',\n \"\",\n \" local ip_count\",\n \" ip_count=$(echo \\\"$ip_issues\\\" | jq 'length')\",\n \"\",\n ' if [[ \"$ip_count\" -gt 0 ]]; then',\n \" local ip_threshold\",\n \" ip_threshold=$(date -u -v-${STALE_IN_PROGRESS_HOURS}H +%Y-%m-%dT%H:%M:%S 2>/dev/null \\\\\",\n ' || date -u -d \"${STALE_IN_PROGRESS_HOURS} hours ago\" +%Y-%m-%dT%H:%M:%S 2>/dev/null)',\n \"\",\n \" local ip_data\",\n ' ip_data=$(echo \"$ip_issues\" | jq -r \\'.[] | \"\\\\(.number)\\\\t\\\\(.title)\\\\t\\\\(.updatedAt)\"\\')',\n \"\",\n \" while IFS=$'\\\\t' read -r num title updated; do\",\n ' [[ -z \"$num\" ]] && continue',\n ' local updated_trimmed=\"${updated%%+*}\"',\n ' updated_trimmed=\"${updated_trimmed%%Z*}\"',\n ' if [[ \"$updated_trimmed\" < \"$ip_threshold\" ]]; then',\n ' local date_part=\"${updated_trimmed%%T*}\"',\n ' echo \"STALE #${num} — no activity since ${date_part} — \\\\\"${title}\\\\\"\"',\n \" fi\",\n ' done <<< \"$ip_data\"',\n \" fi\",\n \"\",\n \" # Check blocked issues\",\n \" local bl_issues\",\n ' bl_issues=$(gh issue list --label \"status:blocked\" --state open \\\\',\n ' --json number,title,updatedAt --limit 50 2>/dev/null || echo \"[]\")',\n \"\",\n \" local bl_count\",\n \" bl_count=$(echo \\\"$bl_issues\\\" | jq 'length')\",\n \"\",\n ' if [[ \"$bl_count\" -gt 0 ]]; then',\n \" local bl_threshold\",\n \" bl_threshold=$(date -u -v-${STALE_BLOCKED_HOURS}H +%Y-%m-%dT%H:%M:%S 2>/dev/null \\\\\",\n ' || date -u -d \"${STALE_BLOCKED_HOURS} hours ago\" +%Y-%m-%dT%H:%M:%S 2>/dev/null)',\n \"\",\n \" local bl_data\",\n ' bl_data=$(echo \"$bl_issues\" | jq -r \\'.[] | \"\\\\(.number)\\\\t\\\\(.title)\\\\t\\\\(.updatedAt)\"\\')',\n \"\",\n \" while IFS=$'\\\\t' read -r num title updated; do\",\n ' [[ -z \"$num\" ]] && continue',\n ' local updated_trimmed=\"${updated%%+*}\"',\n ' updated_trimmed=\"${updated_trimmed%%Z*}\"',\n ' if [[ \"$updated_trimmed\" < \"$bl_threshold\" ]]; then',\n ' local date_part=\"${updated_trimmed%%T*}\"',\n ' echo \"STALE_BLOCKED #${num} — blocked since ${date_part} — \\\\\"${title}\\\\\"\"',\n \" fi\",\n ' done <<< \"$bl_data\"',\n \" fi\",\n \"\",\n ' if [[ \"$ip_count\" -eq 0 && \"$bl_count\" -eq 0 ]]; then',\n ' echo \"NO_STALE_ISSUES\"',\n \" fi\",\n \"}\",\n \"\",\n \"cmd_orphaned() {\",\n \" # Check for remote branches whose issues are closed or missing\",\n \" git fetch --prune origin 2>/dev/null\",\n \" local branches\",\n ' branches=$(git branch -r --format=\"%(refname:short)\" | grep -v HEAD | sed \"s|origin/||\")',\n \"\",\n \" local found_orphan=false\",\n \" while IFS= read -r branch; do\",\n ' [[ -z \"$branch\" ]] && continue',\n ' [[ \"$branch\" == \"main\" || \"$branch\" == \"master\" ]] && continue',\n \"\",\n \" # Extract issue number from branch name (e.g., feat/42-add-login → 42)\",\n \" local issue_num\",\n \" issue_num=$(echo \\\"$branch\\\" | grep -oE '/[0-9]+' | tr -d '/' | head -1)\",\n ' [[ -z \"$issue_num\" ]] && continue',\n \"\",\n \" local state\",\n ' state=$(gh issue view \"$issue_num\" --json state --jq \\'.state\\' 2>/dev/null || echo \"NOT_FOUND\")',\n \"\",\n ' if [[ \"$state\" == \"CLOSED\" ]]; then',\n \" found_orphan=true\",\n ' echo \"ORPHAN_BRANCH ${branch} — issue #${issue_num} is closed\"',\n ' elif [[ \"$state\" == \"NOT_FOUND\" ]]; then',\n \" found_orphan=true\",\n ' echo \"ORPHAN_BRANCH ${branch} — issue #${issue_num} not found\"',\n \" fi\",\n ' done <<< \"$branches\"',\n \"\",\n \" # Check for open PRs whose linked issues are closed\",\n \" local prs\",\n ' prs=$(gh pr list --state open --json number,title,body --limit 50 2>/dev/null || echo \"[]\")',\n \" local pr_data\",\n ' pr_data=$(echo \"$prs\" | jq -r \\'',\n \" .[] |\",\n ' (.body | capture(\"(?:Closes|Fixes|Resolves) #(?<num>[0-9]+)\") | .num) as $issue |',\n ' \"\\\\(.number)\\\\t\\\\(.title)\\\\t\\\\($issue // \"\")\"',\n \" ' 2>/dev/null)\",\n \"\",\n \" while IFS=$'\\\\t' read -r pr_num title issue_num; do\",\n ' [[ -z \"$pr_num\" || -z \"$issue_num\" ]] && continue',\n ' if is_closed \"$issue_num\"; then',\n \" found_orphan=true\",\n ' echo \"ORPHAN_PR #${pr_num} — linked issue #${issue_num} is closed — \\\\\"${title}\\\\\"\"',\n \" fi\",\n ' done <<< \"$pr_data\"',\n \"\",\n \" if ! $found_orphan; then\",\n ' echo \"NO_ORPHANED_RESOURCES\"',\n \" fi\",\n \"}\",\n \"\",\n \"cmd_prs() {\",\n \" local prs\",\n \" prs=$(gh pr list --state open --json number,title,isDraft,headRefName,labels,body \\\\\",\n ' --limit 50 2>/dev/null || echo \"[]\")',\n \"\",\n \" local count\",\n \" count=$(echo \\\"$prs\\\" | jq 'length')\",\n ' if [[ \"$count\" -eq 0 ]]; then',\n ' echo \"NO_OPEN_PRS\"',\n \" return 0\",\n \" fi\",\n \"\",\n \" # Filter: not draft, no needs-attention label.\",\n \" local eligible\",\n ' eligible=$(echo \"$prs\" | jq -r \\'',\n \" .[] |\",\n \" select(.isDraft == false) |\",\n ' select(.labels | map(.name) | index(\"status:needs-attention\") | not) |',\n ' (.body | capture(\"(?:Closes|Fixes|Resolves) #(?<num>[0-9]+)\") | .num) as $issue |',\n ' \"\\\\(.number)\\\\t\\\\(.title)\\\\t\\\\(.headRefName)\\\\t\\\\($issue // \"\")\"',\n \" ' 2>/dev/null)\",\n \"\",\n ' if [[ -z \"$eligible\" ]]; then',\n ' echo \"NO_ELIGIBLE_PRS\"',\n \" return 0\",\n \" fi\",\n \"\",\n \" while IFS=$'\\\\t' read -r pr_num title branch issue_num; do\",\n ' [[ -z \"$pr_num\" ]] && continue',\n \"\",\n ' if [[ -z \"$issue_num\" ]]; then',\n ' echo \"SKIP PR #${pr_num} — no linked issue — \\\\\"${title}\\\\\"\"',\n \" continue\",\n \" fi\",\n \"\",\n \" # Check CI status\",\n \" local failing_checks\",\n ' failing_checks=$(gh pr checks \"$pr_num\" --json name,state \\\\',\n ' --jq \\'[.[] | select(.state != \"SUCCESS\" and .state != \"SKIPPED\")] | length\\' 2>/dev/null || echo \"-1\")',\n \"\",\n ' if [[ \"$failing_checks\" == \"-1\" ]]; then',\n ' echo \"SKIP PR #${pr_num} — could not read CI status — \\\\\"${title}\\\\\"\"',\n \" continue\",\n \" fi\",\n \"\",\n ' if [[ \"$failing_checks\" -gt 0 ]]; then',\n ' echo \"SKIP PR #${pr_num} — ${failing_checks} CI check(s) not passing — \\\\\"${title}\\\\\"\"',\n \" continue\",\n \" fi\",\n \"\",\n \" # Check if already approved\",\n \" local approved\",\n ' approved=$(gh pr view \"$pr_num\" --json reviews \\\\',\n ' --jq \\'[.reviews[] | select(.state == \"APPROVED\")] | length\\' 2>/dev/null || echo \"0\")',\n ' if [[ \"$approved\" -gt 0 ]]; then',\n ' echo \"SKIP PR #${pr_num} — already approved — \\\\\"${title}\\\\\"\"',\n \" continue\",\n \" fi\",\n \"\",\n ' echo \"REVIEW PR #${pr_num} issue:#${issue_num} branch:${branch} — \\\\\"${title}\\\\\"\"',\n ' done <<< \"$eligible\"',\n \"}\",\n \"\",\n \"# ── main ─────────────────────────────────────────────────────────────\",\n \"\",\n 'case \"${1:-help}\" in',\n ' unblock) shift; cmd_unblock \"$@\" ;;',\n ' eligible) shift; cmd_eligible \"$@\" ;;',\n ' stale) shift; cmd_stale \"$@\" ;;',\n ' orphaned) shift; cmd_orphaned \"$@\" ;;',\n ' prs) shift; cmd_prs \"$@\" ;;',\n \" help|*)\",\n ' echo \"Usage: check-blocked.sh <unblock|eligible|stale|orphaned|prs>\"',\n \" exit 1\",\n \" ;;\",\n \"esac\",\n ].join(\"\\n\"),\n};\n\n/*******************************************************************************\n *\n * Orchestrator sub-agent\n *\n ******************************************************************************/\n\nconst orchestratorSubAgent: AgentSubAgent = {\n name: \"orchestrator\",\n description:\n \"Pipeline manager that reviews PRs, triages issues, and identifies the next work item — never implements code\",\n model: AGENT_MODEL.POWERFUL,\n maxTurns: 100,\n platforms: { cursor: { exclude: true } },\n prompt: [\n \"# Orchestrator Agent\",\n \"\",\n \"You are a pipeline manager for the **{{repository.owner}}/{{repository.name}}** repository.\",\n \"You review PRs, triage issues, and identify the next work item. You **never**\",\n \"implement code, create branches for issues, or claim issues.\",\n \"\",\n \"Run the same loop every invocation. Execute all phases in order.\",\n \"\",\n \"---\",\n \"\",\n ...PROJECT_CONTEXT_READER_SECTION,\n \"## Phase A: Startup\",\n \"\",\n \"```bash\",\n \"git checkout main && git pull origin main\",\n \"```\",\n \"\",\n \"## Phase B: Batch PR Review\",\n \"\",\n \"Find all PRs eligible for review:\",\n \"\",\n \"```bash\",\n \".claude/procedures/check-blocked.sh prs\",\n \"```\",\n \"\",\n \"For each `REVIEW PR #N issue:#M branch:<branch>` line:\",\n \"\",\n \"1. Check out the PR branch: `gh pr checkout N`\",\n \"2. Review the PR:\",\n \" - Read the PR description and linked issue: `gh pr view N`\",\n \" - Review the diff: `gh pr diff N`\",\n \" - Check all changed files for correctness, conventions, and test coverage\",\n \" - Verify PR conventions: conventional commit title, closing keyword, summary present\",\n \" - Check CI status: `gh pr checks N`\",\n \"3. If the PR passes review:\",\n \" - Enable squash auto-merge: `gh pr merge N --auto --squash --subject '<conventional-commit-title>' --body '<extended-description>'`\",\n \"4. If the PR fails review:\",\n \" - Request changes: `gh pr review N --request-changes --body '<findings>'`\",\n \"5. After each PR (whether merged or not):\",\n \" ```bash\",\n \" git checkout main && git pull origin main\",\n \" ```\",\n \"\",\n \"Skip lines starting with `SKIP` — those PRs are not eligible.\",\n \"If output is `NO_OPEN_PRS` or `NO_ELIGIBLE_PRS`, skip to Phase C.\",\n \"\",\n \"## Phase C: Triage — Unblock\",\n \"\",\n \"Check for blocked issues whose dependencies have resolved:\",\n \"\",\n \"```bash\",\n \".claude/procedures/check-blocked.sh unblock\",\n \"```\",\n \"\",\n \"For each `UNBLOCK #N` line:\",\n \"```bash\",\n 'gh issue edit N --remove-label \"status:blocked\" --add-label \"status:ready\"',\n 'gh issue comment N --body \"Dependencies resolved — unblocking.\"',\n \"```\",\n \"\",\n \"For `BLOCKED #N — no Depends on field found`: leave as-is (Phase D will\",\n \"catch it if it's been blocked too long).\",\n \"\",\n \"If output is `NO_BLOCKED_ISSUES`, skip to Phase D.\",\n \"\",\n \"## Phase D: Maintenance\",\n \"\",\n \"### D1: Stale Detection\",\n \"\",\n \"```bash\",\n \".claude/procedures/check-blocked.sh stale\",\n \"```\",\n \"\",\n \"For each `STALE #N` line (in-progress >72h without activity):\",\n \"```bash\",\n 'gh issue edit N --add-label \"status:needs-attention\"',\n 'gh issue comment N --body \"Flagged: in-progress for >3 days with no activity.\"',\n \"```\",\n \"\",\n \"For each `STALE_BLOCKED #N` line (blocked >168h):\",\n \"```bash\",\n 'gh issue edit N --add-label \"status:needs-attention\"',\n 'gh issue comment N --body \"Flagged: blocked for >7 days — may need human intervention.\"',\n \"```\",\n \"\",\n \"**Important:** Do NOT auto-reset stale issues to `status:ready` — partial\",\n \"implementation work may exist on a branch.\",\n \"\",\n \"### D2: Orphaned Detection\",\n \"\",\n \"```bash\",\n \".claude/procedures/check-blocked.sh orphaned\",\n \"```\",\n \"\",\n \"Report any `ORPHAN_BRANCH` or `ORPHAN_PR` lines. These indicate branches\",\n \"or PRs whose linked issues are closed or missing. Log them for visibility\",\n \"but do not delete branches automatically.\",\n \"\",\n \"### D3: Needs-Attention Summary\",\n \"\",\n \"List all issues currently flagged:\",\n \"```bash\",\n 'gh issue list --label \"status:needs-attention\" --state open --json number,title',\n \"```\",\n \"\",\n \"Log the count and titles for operator visibility.\",\n \"\",\n \"## Phase E: Queue Scan\",\n \"\",\n \"Find the highest-priority ready issue:\",\n \"\",\n \"```bash\",\n \".claude/procedures/check-blocked.sh eligible\",\n \"```\",\n \"\",\n \"If a `PICK` line is returned, report it as:\",\n \"```\",\n 'NEXT_WORK_ITEM #<number> priority:<level> type:<label> \"<title>\"',\n \"```\",\n \"\",\n \"If output is `NO_READY_ISSUES`, report that the queue is empty.\",\n \"\",\n \"**Do NOT claim the issue, create a branch, or start implementation.**\",\n \"The worker agent handles that.\",\n \"\",\n \"## Phase F: Cleanup\",\n \"\",\n \"```bash\",\n \"git checkout main && git pull origin main\",\n \"git fetch --prune origin\",\n \"```\",\n \"\",\n \"Log completion: phases executed, PRs reviewed, issues unblocked,\",\n \"stale issues flagged, and next work item (if any).\",\n \"\",\n \"---\",\n \"\",\n \"## Rules\",\n \"\",\n \"1. **Never implement code.** You triage, review, and report — you do not code.\",\n \"2. **Never claim issues.** Do not add `status:in-progress` or create branches for issues.\",\n \"3. **Always use check-blocked.sh.** All triage queries go through the shell script for token efficiency.\",\n \"4. **Follow CLAUDE.md conventions** for all git and gh operations.\",\n \"5. **Priority order:** critical > high > medium > low > trivial, then FIFO by issue number.\",\n ].join(\"\\n\"),\n};\n\n/*******************************************************************************\n *\n * Issue Worker sub-agent — selects and works on the next ready issue\n *\n ******************************************************************************/\n\nconst issueWorkerSubAgent: AgentSubAgent = {\n name: \"issue-worker\",\n description:\n \"Selects the next ready issue from the queue, claims it, and implements the change end-to-end following repository conventions\",\n model: AGENT_MODEL.POWERFUL,\n maxTurns: 50,\n canDelegateToAgents: [],\n platforms: { cursor: { exclude: true } },\n prompt: [\n \"# Issue Worker\",\n \"\",\n \"You are the issue worker for **{{repository.owner}}/{{repository.name}}**.\",\n \"Your job is to pick the next issue from the queue, claim it, and implement\",\n \"the change end-to-end — from branch creation through to opening a PR.\",\n \"\",\n \"---\",\n \"\",\n \"## Invocation Mode\",\n \"\",\n \"You operate in one of two modes:\",\n \"\",\n \"- **Interactive mode (default):** A human invoked you directly. You must\",\n \" pause and request explicit user approval before committing code (Phase 6).\",\n \"- **Scheduled mode:** A scheduled task or automation invoked you. You commit,\",\n \" push, and open the PR autonomously without pausing.\",\n \"\",\n \"**You are in scheduled mode if and only if the invocation prompt that\",\n \"started this session contains the literal phrase `scheduled mode` (or\",\n \"`non-interactive`).** Otherwise, default to interactive mode. When in\",\n \"doubt, treat the session as interactive — pausing for approval is always\",\n \"safe; committing without approval is not.\",\n \"\",\n \"---\",\n \"\",\n ...PROJECT_CONTEXT_READER_SECTION,\n \"## Phase 1: Select an Issue\",\n \"\",\n \"If an issue number was provided in your instructions, use that issue.\",\n \"Otherwise, find the next issue to work on:\",\n \"\",\n \"```bash\",\n \".claude/procedures/check-blocked.sh eligible\",\n \"```\",\n \"\",\n \"This returns issues sorted by priority (critical > high > medium > low > trivial),\",\n \"then by issue number (FIFO). Take the **first** `PICK` line.\",\n \"\",\n \"If the output is `NO_READY_ISSUES`, report that the queue is empty and stop.\",\n \"\",\n \"If any `SKIP` lines appear, ignore them — those issues have unresolved dependencies.\",\n \"\",\n \"## Phase 2: Claim the Issue\",\n \"\",\n \"```bash\",\n 'gh issue edit <number> --remove-label \"status:ready\" --add-label \"status:in-progress\"',\n \"```\",\n \"\",\n \"Read the full issue details:\",\n \"```bash\",\n \"gh issue view <number>\",\n \"```\",\n \"\",\n \"## Phase 3: Set Up\",\n \"\",\n \"```bash\",\n \"git checkout {{repository.defaultBranch}} && git pull origin {{repository.defaultBranch}}\",\n \"```\",\n \"\",\n \"Determine the branch type from the issue's `type:*` label or title prefix:\",\n \"\",\n \"| Label / prefix | Branch type |\",\n \"|---------------|-------------|\",\n \"| `type:feat` / `feat:` | `feat/` |\",\n \"| `type:fix` / `fix:` | `fix/` |\",\n \"| `type:chore` / `chore:` | `chore/` |\",\n \"| `type:refactor` / `refactor:` | `refactor/` |\",\n \"| `type:docs` / `docs:` | `docs/` |\",\n \"| `type:release` / `release:` | `release/` |\",\n \"| `type:hotfix` / `hotfix:` | `hotfix/` |\",\n \"| No type label | `feat/` (default) |\",\n \"\",\n \"Create a branch following the naming convention:\",\n \"```bash\",\n \"git checkout -b <type>/<issue-number>-<slug>\",\n \"```\",\n \"\",\n \"The slug should be a short (3-5 word) kebab-case summary derived from the issue title.\",\n \"\",\n \"Link the branch to the issue:\",\n \"```bash\",\n \"gh issue comment <number> --body 'Branch: `<branch-name>`'\",\n \"```\",\n \"\",\n \"## Phase 4: Implement\",\n \"\",\n \"Read the issue body carefully. Understand the acceptance criteria.\",\n \"\",\n \"Implement the change following these guidelines based on issue type:\",\n \"\",\n \"- **feat**: Implement the new feature. Add tests. Export public APIs from `index.ts`.\",\n \"- **fix**: Reproduce the bug first. Write a failing test. Fix the bug. Verify the test passes.\",\n \"- **chore**: Make the maintenance change. Verify no regressions.\",\n \"- **refactor**: Restructure code without changing behavior. Existing tests must pass unchanged.\",\n \"- **docs**: Update documentation only. Do not change source code.\",\n \"\",\n \"Follow all conventions from CLAUDE.md and the project's agent rules.\",\n \"\",\n \"## Phase 5: Verify\",\n \"\",\n \"Run the appropriate verification commands depending on what changed:\",\n \"\",\n \"1. If Projen config was changed: `npx projen && pnpm install`\",\n \"2. Compile the affected package: `pnpm --filter @codedrifters/<package> compile`\",\n \"3. Test the affected package: `pnpm --filter @codedrifters/<package> test`\",\n \"4. If changes span multiple packages: `pnpm build:all`\",\n \"\",\n \"Fix any compilation errors, test failures, or lint errors before proceeding.\",\n \"\",\n \"## Phase 6: Commit and Push\",\n \"\",\n \"**If you are in interactive mode, pause here.** Before running any `git\",\n \"commit`, present the user with a summary of the proposed changes:\",\n \"\",\n \"```bash\",\n \"git status\",\n \"git diff --stat\",\n \"```\",\n \"\",\n \"Then state the conventional commit message you intend to use and ask for\",\n \"explicit approval to commit, push, and open the PR. Do **not** proceed to\",\n \"`git commit` until the user replies with an affirmative response (e.g.,\",\n '\"yes\", \"approved\", \"go ahead\"). If the user requests changes, address',\n \"them and ask again.\",\n \"\",\n \"**If you are in scheduled mode, skip the pause and proceed directly.**\",\n \"\",\n \"Use conventional commit messages:\",\n \"```bash\",\n \"git add <files>\",\n 'git commit -m \"<type>: <description>\"',\n \"git push -u origin <branch-name>\",\n \"```\",\n \"\",\n \"## Phase 7: Open a PR\",\n \"\",\n \"```bash\",\n 'gh pr create --title \"<type>(<scope>): <description>\" --body \"## Summary',\n \"\",\n \"<bullet points>\",\n \"\",\n 'Closes #<issue-number>\"',\n \"```\",\n \"\",\n \"Do **not** enable auto-merge yourself. The `pr-reviewer` sub-agent owns\",\n \"review and merge for every PR — it verifies the diff against the issue's\",\n \"acceptance criteria and enables squash auto-merge only when all checks\",\n \"pass. Record the new PR number so a reviewer can be invoked next.\",\n \"\",\n \"## Phase 8: Update Status\",\n \"\",\n \"After the PR is created, transition the issue to the review phase:\",\n \"```bash\",\n 'gh issue edit <number> --remove-label \"status:in-progress\" --add-label \"status:ready-for-review\"',\n \"```\",\n \"\",\n \"Do **not** set `status:done` here — the `pr-reviewer` sub-agent is\",\n \"responsible for that transition once the PR successfully merges.\",\n \"\",\n \"## Phase 9: Branch Cleanup\",\n \"\",\n \"The PR will not auto-merge until the `pr-reviewer` enables it. Poll the PR\",\n \"state up to 10 times, waiting 30 seconds between polls, until it either\",\n \"merges, closes, or the timeout is reached:\",\n \"\",\n \"```bash\",\n \"gh pr view <pr-number> --json state --jq '.state'\",\n \"```\",\n \"\",\n \"- **If the state becomes `MERGED`:** clean up the local branch.\",\n \" ```bash\",\n \" git checkout {{repository.defaultBranch}}\",\n \" git pull origin {{repository.defaultBranch}}\",\n \" git branch -D <branch-name>\",\n \" ```\",\n \"- **If the state becomes `CLOSED` (not merged):** leave the branch in place\",\n \" and report that the PR was closed without merging. Do not delete the branch.\",\n \"- **If still `OPEN` after the polling window:** report that the PR is\",\n \" awaiting review/merge and stop. Do not delete the branch.\",\n \"\",\n \"---\",\n \"\",\n \"## Rules\",\n \"\",\n \"1. **One issue per session.** Process exactly ONE issue, then stop.\",\n \"2. **Use check-blocked.sh.** Always use the procedure script for issue selection.\",\n \"3. **Follow CLAUDE.md conventions** for branch naming, commits, and PRs.\",\n \"4. **Do not assign PRs to a project board** — this repo has no GitHub project.\",\n \"5. **Do not add AI co-author** attribution to commits.\",\n \"6. **On failure:** If you cannot complete the issue, update labels and leave a comment:\",\n \" ```bash\",\n ' gh issue edit <number> --remove-label \"status:in-progress\" --add-label \"status:needs-attention\"',\n ' gh issue comment <number> --body \"Worker could not complete: <reason>\"',\n \" ```\",\n ].join(\"\\n\"),\n};\n\n/*******************************************************************************\n *\n * Bundle definition\n *\n ******************************************************************************/\n\nexport const orchestratorBundle: AgentRuleBundle = {\n name: \"orchestrator\",\n description:\n \"Pipeline orchestrator agent for issue triage, PR review, and queue management\",\n\n // Always included by default\n appliesWhen: () => true,\n\n rules: [\n {\n name: \"orchestrator-conventions\",\n description:\n \"Guidelines for orchestrator agent behavior and pipeline management\",\n scope: AGENT_RULE_SCOPE.ALWAYS,\n content: [\n \"# Orchestrator Conventions\",\n \"\",\n \"When running the orchestrator agent (`.claude/agents/orchestrator.md`):\",\n \"\",\n \"- The orchestrator **never** implements code or creates branches for issues\",\n \"- It reviews PRs, triages issues, and reports the next work item\",\n \"- All triage queries use `.claude/procedures/check-blocked.sh` for token efficiency\",\n \"- Priority order: critical > high > medium > low > trivial, then FIFO\",\n \"- Stale thresholds: 72h for in-progress, 168h for blocked\",\n \"- Flagged issues get `status:needs-attention` — they are not auto-reset\",\n ].join(\"\\n\"),\n platforms: {\n claude: { target: \"claude-md\" as const },\n cursor: { exclude: true },\n },\n tags: [\"workflow\"],\n },\n ],\n\n subAgents: [orchestratorSubAgent, issueWorkerSubAgent],\n\n procedures: [checkBlockedProcedure],\n\n claudePermissions: {\n allow: [\n // Allow executing the check-blocked.sh procedure\n \"Bash(.claude/procedures/*.sh *)\",\n ],\n },\n};\n","import { AgentRuleBundle } from \"../agent-config-options\";\nimport { PROJECT_CONTEXT_READER_SECTION } from \"./project-context\";\nimport {\n AGENT_MODEL,\n AGENT_RULE_SCOPE,\n AgentSkill,\n AgentSubAgent,\n} from \"../types\";\n\n/**\n * Sub-agent that researches and profiles individual people into\n * structured markdown. Produces one profile per person and maintains\n * cross-references to related companies, software, and meeting notes.\n *\n * The prompt deliberately avoids hardcoded domains, companies, or source\n * projects. Consumers configure the person-role taxonomy scope, output\n * paths, cross-reference targets, and refresh cadence via the skill\n * invocation and by extending the rule in their own `agentConfig.rules`.\n */\nconst peopleProfileAnalystSubAgent: AgentSubAgent = {\n name: \"people-profile-analyst\",\n description:\n \"Researches an individual person (colleague, customer contact, vendor contact, partner contact, industry expert, or connector) from public sources and produces a structured markdown profile cross-linked to companies, software, and meeting notes. One person per session, tracked by people:* GitHub issue labels.\",\n model: AGENT_MODEL.POWERFUL,\n maxTurns: 80,\n platforms: { cursor: { exclude: true } },\n prompt: [\n \"# People Profile Analyst Agent\",\n \"\",\n \"You research a single person from public sources and write a\",\n \"structured markdown profile. Each profile cycle runs across a small\",\n \"sequence of GitHub issues — one per phase — and produces a single\",\n \"profile file on disk plus cross-references to related entities\",\n \"(companies, software, meeting notes) already tracked elsewhere in\",\n \"the project.\",\n \"\",\n \"This agent is **domain-neutral**. It makes no assumptions about what\",\n \"the consuming project sells, which industry it serves, or which\",\n \"people matter to it. All domain-specific vocabulary, output\",\n \"locations, cross-reference targets, and profile-template overrides\",\n \"come from the invoking issue body or the consuming project's\",\n \"configuration.\",\n \"\",\n \"Follow your project's shared agent conventions (`AGENTS.md`,\",\n \"`CLAUDE.md`, or equivalent) for all commit, branch, and PR rules.\",\n \"\",\n \"---\",\n \"\",\n ...PROJECT_CONTEXT_READER_SECTION,\n \"## Design Principles\",\n \"\",\n \"1. **One person per session.** Never profile two people in a single\",\n \" session, even if they came up together (e.g. co-founders).\",\n \"2. **Public sources only.** Use the person's own public writing,\",\n \" company bios, conference talks, public interviews, and similar\",\n \" public material. Do not attempt to access gated or paywalled\",\n \" content unless the invoking issue body explicitly authorizes it.\",\n \"3. **Filesystem durability.** The profile file is the deliverable. It\",\n \" is committed to disk before the profile issue closes. Downstream\",\n \" phases read from disk — never rely on session memory.\",\n \"4. **Generic over specific.** No hardcoded role types, taxonomies, or\",\n \" relationship assumptions. Use the generic person-role taxonomy\",\n \" below and let consuming projects override it.\",\n \"5. **Cite everything.** Every non-trivial factual claim in the\",\n \" profile must carry a source citation (URL plus access date).\",\n \"6. **Respect privacy.** Profile only public, professional information.\",\n \" Never capture home addresses, personal phone numbers, family\",\n \" details, health information, or other private data even when\",\n \" encountered in public sources.\",\n \"7. **Cross-reference, don't duplicate.** When the profile mentions a\",\n \" company, software product, or meeting already tracked by the\",\n \" consuming project, link to the existing artifact rather than\",\n \" duplicating its content. Do not create downstream research\",\n \" issues for these cross-references — only link.\",\n \"\",\n \"---\",\n \"\",\n \"## Person Role Taxonomy\",\n \"\",\n \"Pick exactly one role per person profile. The taxonomy is\",\n \"deliberately generic — consuming projects override it via\",\n \"`agentConfig.rules` if they need a domain-specific refinement.\",\n \"\",\n \"| Role | Use for |\",\n \"|------|---------|\",\n \"| `colleague` | People inside your own organization worth tracking (teammates, cross-functional partners, leadership). |\",\n \"| `customer-contact` | Named individuals at existing or prospective customer accounts. |\",\n \"| `vendor-contact` | Named individuals at vendors, suppliers, or software providers you depend on. |\",\n \"| `partner-contact` | Named individuals at strategic, channel, or integration partners. |\",\n \"| `industry-expert` | Analysts, researchers, journalists, or well-known practitioners whose work shapes the market. |\",\n \"| `connector` | People who primarily provide introductions, referrals, or access across networks — advisors, investors acting as connectors, community hubs. |\",\n \"\",\n \"If the person plausibly fits two roles, prefer the one that reflects\",\n \"the **reason the profile was requested**, and note the secondary\",\n \"role in the profile body.\",\n \"\",\n \"---\",\n \"\",\n \"## State Machine Overview\",\n \"\",\n \"```\",\n \"┌───────────────────┐ ┌──────────────────────┐ ┌───────────────────┐\",\n \"│ 1. RESEARCH │────▶│ 2. DRAFT PROFILE │────▶│ 3. FOLLOWUP │\",\n \"│ Collect public │ │ Write the structured │ │ Cross-link the │\",\n \"│ sources into a │ │ markdown profile to │ │ profile to existing│\",\n \"│ bounded notes │ │ the configured path │ │ companies, software│\",\n \"│ file │ │ │ │ and meeting notes │\",\n \"└───────────────────┘ └──────────────────────┘ └───────────────────┘\",\n \"```\",\n \"\",\n \"**Issue labels encode the phase:**\",\n \"\",\n \"| Label | Phase | Session work |\",\n \"|-------|-------|-------------|\",\n \"| `people:research` | 1. Research | Gather public sources. Write a bounded research-notes file. Create the draft issue. |\",\n \"| `people:draft` | 2. Draft | Read the research notes. Write the structured profile to `<PROFILES_DIR>`. Create the followup issue if warranted. |\",\n \"| `people:followup` | 3. Followup | Read the profile. Update cross-references to existing companies, software, and meeting notes. No new downstream issues. |\",\n \"\",\n \"All issues also carry `type:people-profile` and a `status:*` label.\",\n \"\",\n \"**Issue count per person cycle:** 1 research + 1 draft + 0–1 followup =\",\n \"**2–3 sessions**. The followup phase is skipped when the profile did\",\n \"not surface any cross-references worth linking.\",\n \"\",\n \"**Shortened paths:**\",\n \"- Research phase determines the person is out of scope (not\",\n \" relevant, insufficient public material) → research issue closes\",\n \" with a justification and no downstream issues are created → **1 session**.\",\n \"- Short profile with no cross-references needed → **2 sessions**.\",\n \"\",\n \"---\",\n \"\",\n \"## Configurable Paths\",\n \"\",\n \"The pipeline uses these placeholders. Consuming projects override the\",\n \"defaults by passing paths in the `/profile-person` skill invocation\",\n \"or by extending this rule in their own `agentConfig.rules`.\",\n \"\",\n \"| Placeholder | Meaning | Default |\",\n \"|-------------|---------|---------|\",\n \"| `<PEOPLE_ROOT>` | Root folder for person profiles | `docs/people/` |\",\n \"| `<PROFILES_DIR>` | Final person profile files | `<PEOPLE_ROOT>/profiles/` |\",\n \"| `<NOTES_DIR>` | Research-notes files from Phase 1 | `<PEOPLE_ROOT>/notes/` |\",\n \"| `<PERSON_SLUG>` | Short kebab-case slug identifying the person | derived from the person's name |\",\n \"| `<COMPANIES_DIR>` | Where existing company profiles live (for cross-references) | `docs/companies/profiles/` |\",\n \"| `<SOFTWARE_DIR>` | Where existing software profiles live (for cross-references) | `docs/software/profiles/` |\",\n \"| `<MEETINGS_DIR>` | Where meeting notes live (for cross-references) | `docs/meetings/` |\",\n \"\",\n \"If `docs/project-context.md` specifies a different people-research\",\n \"tree or cross-reference target, prefer that. Otherwise fall back to\",\n \"the defaults above. Cross-reference directories are read-only — this\",\n \"agent never writes into them.\",\n \"\",\n \"---\",\n \"\",\n \"## Refresh Cadence\",\n \"\",\n \"Profiles go stale. A person changes jobs, publishes new work, or\",\n \"shifts focus. The pipeline supports a configurable refresh cadence:\",\n \"\",\n \"- **Default cadence:** 180 days from the profile's `date` frontmatter.\",\n \"- **Override:** the invoking issue body may specify a `refresh_days: N`\",\n \" field, or the consuming project may set a project-wide default in\",\n \" `docs/project-context.md`.\",\n \"\",\n \"When the `/profile-person` skill is invoked for a slug that already\",\n \"has a profile:\",\n \"\",\n \"- If the profile is **younger** than the refresh cadence, the skill\",\n \" exits with a message pointing to the existing profile. Pass\",\n \" `force: true` in the issue body to refresh anyway.\",\n \"- If the profile is **older** than the refresh cadence, the pipeline\",\n \" proceeds in update-in-place mode: Phase 2 edits the existing file,\",\n \" preserves its slug, and bumps the `date` frontmatter.\",\n \"\",\n \"Refresh mode never changes the profile's role without an explicit\",\n \"override in the refresh request — role changes are material and\",\n \"warrant a human review step.\",\n \"\",\n \"---\",\n \"\",\n \"## Agent Loop\",\n \"\",\n \"Run this loop exactly once per session. Never start a second issue.\",\n \"\",\n \"1. Claim one open `type:people-profile` issue using phase priority:\",\n \" `people:research` > `people:draft` > `people:followup`.\",\n \"2. Transition `status:ready` → `status:in-progress` and create the\",\n \" branch per your project's branch-naming convention.\",\n \"3. Execute the phase handler that matches the issue's `people:*`\",\n \" label.\",\n \"4. Commit, push, open a PR (if applicable), and close the issue per\",\n \" your project's PR workflow.\",\n \"\",\n \"---\",\n \"\",\n \"## Phase 1: Research (`people:research`)\",\n \"\",\n \"**Goal:** Gather public sources into a bounded research-notes file.\",\n \"\",\n \"**Budget:** Public web search only, unless the issue body authorizes\",\n \"additional sources. Write one notes file. Do not write the profile\",\n \"in this phase.\",\n \"\",\n \"### Steps\",\n \"\",\n \"1. **Read the issue body.** It should include:\",\n \" - The person's name and primary affiliation (company) if known\",\n \" - The requested role from the taxonomy above\",\n \" - The reason the profile was requested (framing — what does the\",\n \" invoking project want to learn?)\",\n \" - Optional: `<PERSON_SLUG>` override, custom output paths,\",\n \" `refresh_days` override, `force: true` for out-of-cadence refresh\",\n \"\",\n \"2. **Derive `<PERSON_SLUG>`** if not supplied — a 2–4 word kebab-case\",\n \" summary of the person's name. Disambiguate against any existing\",\n \" slug under `<PROFILES_DIR>/` or `<NOTES_DIR>/` by appending a\",\n \" company or role qualifier (e.g. `jane-doe-acme`).\",\n \"\",\n \"3. **Check for an existing profile.** If `<PROFILES_DIR>/<PERSON_SLUG>.md`\",\n \" exists, read its `date` frontmatter and apply the refresh cadence\",\n \" rules above before proceeding.\",\n \"\",\n \"4. **Gather sources.** Prioritize in this order:\",\n \" - The person's own public writing (personal site, blog, newsletter)\",\n \" - Their current employer's bio / leadership page\",\n \" - Public conference talks, podcast appearances, and interviews\",\n \" - Public directories that the invoking issue body authorizes\",\n \" (LinkedIn, GitHub, company profiles, Crunchbase)\",\n \" - Public contributions (open-source repos, published papers)\",\n \"\",\n \"5. **Write a research-notes file** to\",\n \" `<NOTES_DIR>/<PERSON_SLUG>.notes.md`:\",\n \"\",\n \" ```markdown\",\n \" ---\",\n ' title: \"Research Notes: <person name>\"',\n \" slug: <PERSON_SLUG>\",\n \" role: <one of the taxonomy values>\",\n \" primary_company: <company name if known>\",\n \" date: YYYY-MM-DD\",\n \" parent_issue: <N>\",\n \" ---\",\n \"\",\n \" # Research Notes: <person name>\",\n \"\",\n \" ## Framing\",\n \" <why this person was requested and what to learn>\",\n \"\",\n \" ## Raw Findings\",\n \" - <finding> — source: <citation>\",\n \"\",\n \" ## Candidate Cross-References\",\n \" - **Companies mentioned:** <list of company names>\",\n \" - **Software mentioned:** <list of product names>\",\n \" - **Meetings mentioned:** <list of meeting identifiers>\",\n \"\",\n \" ## Open Questions\",\n \" <anything the notes could not answer from public sources>\",\n \"\",\n \" ## Sources\",\n \" - <source URL or file path> — <date accessed>\",\n \" ```\",\n \"\",\n \"6. **Create the `people:draft` issue** with `Depends on: #<research-issue>`.\",\n \" Its body references the notes file path, the requested role, and\",\n \" any refresh-mode flags.\",\n \"\",\n \"7. **Commit and push** the notes file. Close the research issue.\",\n \"\",\n \"---\",\n \"\",\n \"## Phase 2: Draft Profile (`people:draft`)\",\n \"\",\n \"**Goal:** Write the structured person profile from the research notes.\",\n \"\",\n \"**Budget:** No new web searches unless explicitly needed to fill a\",\n \"gap the notes flagged. Write one profile file.\",\n \"\",\n \"### Steps\",\n \"\",\n \"1. **Read the research-notes file** referenced in the issue body.\",\n \"\",\n \"2. **Check for duplicates / refresh.** If `<PROFILES_DIR>/<PERSON_SLUG>.md`\",\n \" already exists:\",\n \" - In refresh mode, open the existing file and update in place,\",\n \" preserving the slug and bumping the `date` frontmatter.\",\n \" - Otherwise, flag a naming collision and stop — never silently\",\n \" overwrite a non-trivial existing profile.\",\n \"\",\n \"3. **Write the profile** to `<PROFILES_DIR>/<PERSON_SLUG>.md` using\",\n \" the template below. All sections are required; use\",\n \" `_Not available in public sources._` when a section cannot be\",\n \" filled from the notes.\",\n \"\",\n \" ```markdown\",\n \" ---\",\n ' title: \"<person name>\"',\n \" slug: <PERSON_SLUG>\",\n \" role: <one of the taxonomy values>\",\n \" primary_company: <company name>\",\n \" date: YYYY-MM-DD\",\n \" refresh_days: <N, default 180>\",\n \" parent_issue: <N>\",\n \" notes: <NOTES_DIR>/<PERSON_SLUG>.notes.md\",\n \" ---\",\n \"\",\n \" # <person name>\",\n \"\",\n \" ## Summary\",\n \" <2–4 sentence elevator description: who they are, what they do,\",\n \" why they matter to this project>\",\n \"\",\n \" ## Classification\",\n \" - **Primary role:** <taxonomy value>\",\n \" - **Secondary role (if any):** <taxonomy value or `n/a`>\",\n \" - **Relevance to this project:** <1–2 sentences tying the person\",\n \" back to the framing from the notes>\",\n \"\",\n \" ## Current Position\",\n \" - **Company:** <primary company — link to company profile if tracked>\",\n \" - **Title:** <current title>\",\n \" - **Tenure:** <since YYYY, if known>\",\n \" - **Focus areas:** <what they work on day-to-day>\",\n \"\",\n \" ## Background\",\n \" - **Prior roles:** <short reverse-chronological list>\",\n \" - **Education / credentials:** <if publicly disclosed>\",\n \" - **Notable contributions:** <open-source, publications, talks>\",\n \"\",\n \" ## Expertise Signals\",\n \" <topics they write or speak about — each bullet cited to a public\",\n \" source>\",\n \"\",\n \" ## Positioning / Point of View\",\n \" <how they describe their own work and views — use their own\",\n \" language, cited, rather than inferred>\",\n \"\",\n \" ## Cross-References\",\n \" - **Companies:** <links to `<COMPANIES_DIR>/*.md` for companies\",\n \" already tracked by this project>\",\n \" - **Software:** <links to `<SOFTWARE_DIR>/*.md` for software\",\n \" already tracked by this project>\",\n \" - **Meetings:** <links to `<MEETINGS_DIR>/*.md` for meeting notes\",\n \" this person participated in>\",\n \"\",\n \" ## Contact Preferences\",\n \" <public channels only — company email if listed, social handles,\",\n \" speaker inquiry forms. Never private contact info.>\",\n \"\",\n \" ## Risks / Open Questions\",\n \" <what the profile could not answer; flag anything the followup\",\n \" phase should cross-reference>\",\n \"\",\n \" ## Sources\",\n \" - <source URL> — <date accessed>\",\n \" ```\",\n \"\",\n \"4. **Decide whether a followup issue is warranted.** Create a\",\n \" `people:followup` issue (depending on this draft issue) only if\",\n \" the profile's Candidate Cross-References lists at least one\",\n \" company, software product, or meeting already tracked by the\",\n \" consuming project. Otherwise, note in the draft issue's closing\",\n \" comment that no followup is needed.\",\n \"\",\n \"5. **Commit and push** the profile file. Close the draft issue.\",\n \"\",\n \"---\",\n \"\",\n \"## Phase 3: Followup (`people:followup`)\",\n \"\",\n \"**Goal:** Populate the profile's `## Cross-References` section with\",\n \"links to existing artifacts — companies, software, meetings — that\",\n \"the consuming project already tracks.\",\n \"\",\n \"**Budget:** No new web searches. No new downstream research issues.\",\n \"Read the candidate cross-references, resolve them against the\",\n \"configured directories, update the profile.\",\n \"\",\n \"### Steps\",\n \"\",\n \"1. **Read the profile file** referenced in the issue body.\",\n \"\",\n \"2. **Resolve company cross-references.** For each company named in\",\n \" the profile's research notes or body text, look for a matching\",\n \" file under `<COMPANIES_DIR>/`. If found, link it under\",\n \" `## Cross-References > Companies`. If not found, leave a TODO\",\n \" comment naming the company — the invoking project's team decides\",\n \" whether to kick off a separate company-profile pipeline.\",\n \"\",\n \"3. **Resolve software cross-references.** Same pattern against\",\n \" `<SOFTWARE_DIR>/`. Link what matches; leave TODOs for what\",\n \" doesn't.\",\n \"\",\n \"4. **Resolve meeting cross-references.** For meetings the person\",\n \" participated in, look for a matching file under `<MEETINGS_DIR>/`\",\n \" by date or slug. Link matches; leave TODOs otherwise.\",\n \"\",\n \"5. **Do not open downstream issues.** This pipeline emits no\",\n \" `company:research`, `research:scope`, or similar issues. Cross-\",\n \" references are link-only; downstream research is a separate\",\n \" human decision.\",\n \"\",\n \"6. **Commit and push** the updated profile. Close the followup issue.\",\n \"\",\n \"---\",\n \"\",\n \"## Output Boundaries\",\n \"\",\n \"This agent writes **only** to:\",\n \"\",\n \"- `<NOTES_DIR>/` — research-notes files (Phase 1)\",\n \"- `<PROFILES_DIR>/` — person profiles (Phase 2, updated in Phase 3)\",\n \"\",\n \"The pipeline produces **profiles and notes only**. It does not\",\n \"create new companies, software evaluations, meeting notes, or any\",\n \"other downstream artifacts — it only links to those that already\",\n \"exist under the configured cross-reference directories. Keep this\",\n \"boundary clean so the people-profile pipeline stays generic and\",\n \"cheap to run.\",\n \"\",\n \"---\",\n \"\",\n \"## Rules\",\n \"\",\n \"- **One person per session.** Never profile two people back-to-back.\",\n \"- **Persist before closing.** Every phase must write its output file\",\n \" before closing its issue.\",\n \"- **Cite everything.** Profile claims without source citations do not\",\n \" belong in the deliverable.\",\n \"- **Respect privacy.** Never record private contact details, family\",\n \" information, or other non-professional personal data, even when\",\n \" encountered in a public source.\",\n \"- **Cross-reference, don't duplicate.** Link to existing company,\",\n \" software, and meeting artifacts rather than re-describing them.\",\n \"- **No downstream issue creation.** Phase 3 emits no new research,\",\n \" profile, or requirement issues. Only link.\",\n \"- **Refresh, don't fork.** When a profile exists and is past its\",\n \" cadence, update in place rather than creating a new slug.\",\n ].join(\"\\n\"),\n};\n\n/** Skill that kicks off a people profile cycle. */\nconst profilePersonSkill: AgentSkill = {\n name: \"profile-person\",\n description:\n \"Kick off a people-profile pipeline. Creates a people:research issue for the given person and dispatches Phase 1 (Research) in the people-profile-analyst agent.\",\n disableModelInvocation: true,\n userInvocable: true,\n context: \"fork\",\n agent: \"people-profile-analyst\",\n platforms: { cursor: { exclude: true } },\n instructions: [\n \"# Profile Person\",\n \"\",\n \"Kick off a people-profile pipeline. Creates a `people:research`\",\n \"issue carrying the person's name, role, primary affiliation, and\",\n \"framing, then dispatches Phase 1 (Research) in the\",\n \"people-profile-analyst agent.\",\n \"\",\n \"## Usage\",\n \"\",\n \"/profile-person <person-name>\",\n \"\",\n \"Optional extensions in the issue body:\",\n \"- `role: <colleague | customer-contact | vendor-contact |\",\n \" partner-contact | industry-expert | connector>` — override the\",\n \" default role inference\",\n \"- `company: <name>` — primary company affiliation if not obvious\",\n \" from the name\",\n \"- `framing: <text>` — why this profile was requested and what to learn\",\n \"- `slug: <kebab-case>` — override the derived person slug\",\n \"- `refresh_days: <N>` — override the default 180-day refresh cadence\",\n \"- `force: true` — refresh even if the profile is younger than the\",\n \" cadence window\",\n \"- `sources: <list>` — additional authorized sources beyond public web\",\n \"\",\n \"## Default Paths\",\n \"\",\n \"If the project has no override in `docs/project-context.md` or\",\n \"`agentConfig.rules`, outputs land under:\",\n \"\",\n \"- `docs/people/notes/<slug>.notes.md`\",\n \"- `docs/people/profiles/<slug>.md`\",\n \"\",\n \"Cross-references are resolved against:\",\n \"\",\n \"- `docs/companies/profiles/`\",\n \"- `docs/software/profiles/`\",\n \"- `docs/meetings/`\",\n \"\",\n \"## Steps\",\n \"\",\n \"1. Create a `people:research` issue with `type:people-profile`,\",\n \" `priority:medium`, and `status:ready`. Body must include the\",\n \" person's name, selected role, primary company, framing, and any\",\n \" overrides.\",\n \"2. Execute Phase 1 (Research) of the people-profile-analyst agent.\",\n \"3. Phase 1 creates the `people:draft` issue. Phase 2 may create a\",\n \" `people:followup` issue. Each downstream issue declares its\",\n \" `Depends on:` predecessor.\",\n \"\",\n \"## Output\",\n \"\",\n \"- A research-notes file under the project's notes directory\",\n \"- A single person profile under the profiles directory\",\n \"- Cross-references to existing companies, software, and meetings\",\n \" tracked elsewhere in the project\",\n \"- This pipeline produces **profiles only** — it does not create\",\n \" companies, software, meetings, or any other downstream artifacts.\",\n ].join(\"\\n\"),\n};\n\n/**\n * People-profile bundle — enabled by default.\n *\n * Consuming projects can disable it with\n * `excludeBundles: [\"people-profile\"]`. `appliesWhen` always returns\n * `true` per this batch's directive that bundles assume peers are\n * present.\n *\n * Ships a sub-agent (`people-profile-analyst`), a user-invocable skill\n * (`/profile-person`), and `type:people-profile` plus `people:*` phase\n * labels.\n */\nexport const peopleProfileBundle: AgentRuleBundle = {\n name: \"people-profile\",\n description:\n \"People research and profiling pipeline: research, draft profile, followup. Enabled by default; domain-neutral; filesystem-durable between phases; cross-references existing companies, software, and meeting notes without creating new downstream issues.\",\n appliesWhen: () => true,\n rules: [\n {\n name: \"people-profile-workflow\",\n description:\n \"Describes the 3-phase people-profile pipeline, the people:* label taxonomy, the cross-reference model, and the boundary against downstream research agents.\",\n scope: AGENT_RULE_SCOPE.ALWAYS,\n content: [\n \"# People Profile Workflow\",\n \"\",\n \"Use `/profile-person <person-name>` to kick off a person\",\n \"research and profiling pipeline. The pipeline runs in up to 3\",\n \"phases — research, draft, followup — each tracked by its own\",\n \"GitHub issue labeled `people:research`, `people:draft`, or\",\n \"`people:followup`. All issues carry `type:people-profile`.\",\n \"\",\n \"The pipeline produces **person profiles only**. Cross-references\",\n \"to companies, software products, and meeting notes are link-only\",\n \"— the followup phase never creates new downstream research,\",\n \"profile, or requirement issues.\",\n \"\",\n \"See the `people-profile-analyst` agent definition for full\",\n \"workflow details, default paths, the person-role taxonomy, the\",\n \"refresh cadence rules, and phase-by-phase instructions.\",\n ].join(\"\\n\"),\n platforms: {\n cursor: { exclude: true },\n },\n tags: [\"workflow\"],\n },\n ],\n skills: [profilePersonSkill],\n subAgents: [peopleProfileAnalystSubAgent],\n labels: [\n {\n name: \"type:people-profile\",\n color: \"0E8A16\",\n description:\n \"Work that produces or maintains a person profile or its research notes\",\n },\n {\n name: \"people:research\",\n color: \"C5DEF5\",\n description:\n \"Phase 1: gather public sources about a person into a research-notes file\",\n },\n {\n name: \"people:draft\",\n color: \"BFDADC\",\n description:\n \"Phase 2: write the structured person profile from research notes\",\n },\n {\n name: \"people:followup\",\n color: \"D4C5F9\",\n description:\n \"Phase 3: cross-link the profile to existing companies, software, and meeting notes\",\n },\n ],\n};\n","import { relative } from \"path\";\nimport { Component, Project, YamlFile } from \"projen\";\nimport { ValueOf } from \"type-fest\";\n\n/**\n * Predefined minimum release age values in minutes.\n */\nexport const MINIMUM_RELEASE_AGE = {\n ZERO_DAYS: 0,\n ONE_HOUR: 60,\n SIX_HOURS: 360,\n TWELVE_HOURS: 720,\n ONE_DAY: 1440,\n TWO_DAYS: 2880,\n THREE_DAYS: 4320,\n FOUR_DAYS: 5760,\n FIVE_DAYS: 7200,\n SIX_DAYS: 8640,\n ONE_WEEK: 10080,\n};\n\nexport interface PnpmWorkspaceOptions {\n /**\n * Filename for the pnpm workspace file. This should probably never change.\n *\n * @default \"pnpm-workspace.yaml\"\n */\n readonly fileName?: string;\n\n /**\n * To reduce the risk of installing compromised packages, you can delay the\n * installation of newly published versions. In most cases, malicious releases\n * are discovered and removed from the registry within an hour.\n *\n * minimumReleaseAge defines the minimum number of minutes that must pass\n * after a version is published before pnpm will install it. This applies to\n * all dependencies, including transitive ones.\n *\n * Note: this should match depsUpgradeOptions.cooldown in the project config.\n *\n * See: https://pnpm.io/settings#minimumreleaseage\n *\n * @default MINIMUM_RELEASE_AGE.ONE_DAY\n */\n readonly minimumReleaseAge?: ValueOf<typeof MINIMUM_RELEASE_AGE>;\n\n /**\n * If you set minimumReleaseAge but need certain dependencies to always\n * install the newest version immediately, you can list them under\n * minimumReleaseAgeExclude. The exclusion works by package name and applies\n * to all versions of that package.\n *\n * @default - no exclusions (empty array)\n *\n * See: https://pnpm.io/settings#minimumreleaseageexclude\n */\n readonly minimumReleaseAgeExclude?: Array<string>;\n\n /**\n * A list of package names that are allowed to execute \"preinstall\",\n * \"install\", and/or \"postinstall\" scripts during installation. Only the\n * packages listed in this array will be able to run those lifecycle scripts.\n * If onlyBuiltDependenciesFile and neverBuiltDependencies are omitted, this\n * configuration option will default to blocking all install scripts.\n *\n * You may restrict allowances to specific versions (and lists of versions\n * using a disjunction with ||). When versions are specified, only those\n * versions of the package may run lifecycle scripts:\n *\n * See: https://pnpm.io/settings#onlybuiltdependencies\n *\n * @default none (empty array)\n */\n readonly onlyBuiltDependencies?: Array<string>;\n\n /**\n * A list of package names that are NOT allowed to execute \"preinstall\",\n * \"install\", and/or \"postinstall\" scripts during installation and will not\n * warn or ask to be executed.\n *\n * This is useful when you want to hide the warning because you know the\n * lifecycle scripts are not needed.\n *\n * https://pnpm.io/settings#ignoredbuiltdependencies\n *\n * @default none (empty array)\n */\n readonly ignoredBuiltDependencies?: Array<string>;\n\n /**\n * Additional subproject paths to include in the workspace packages array.\n * These will be combined with any subprojects discovered via projen's\n * project.subprojects property. Paths should be relative to the project root.\n *\n * @default none (empty array)\n */\n readonly subprojects?: Array<string>;\n\n /**\n * Catalog of reusable dependency version ranges.\n *\n * The catalog allows you to define dependency versions as reusable constants\n * that can be referenced in package.json files using the catalog: protocol.\n *\n * Example:\n * ```yaml\n * catalog:\n * react: ^18.0.0\n * typescript: ^5.0.0\n * ```\n *\n * Then in package.json:\n * ```json\n * {\n * \"dependencies\": {\n * \"react\": \"catalog:react\"\n * }\n * }\n * ```\n *\n * @default undefined (not included in output)\n *\n * See: https://pnpm.io/pnpm-workspace_yaml#catalog\n */\n readonly defaultCatalog?: { [key: string]: string };\n\n /**\n * Named catalogs of reusable dependency version ranges.\n *\n * Multiple named catalogs with arbitrarily chosen names can be configured under the namedCatalogs key.\n *\n * Example:\n * ```yaml\n * namedCatalogs:\n * frontend:\n * react: ^18.0.0\n * typescript: ^5.0.0\n * backend:\n * express: ^4.18.0\n * ```\n *\n * Then in package.json:\n * ```json\n * {\n * \"dependencies\": {\n * \"react\": \"catalog:frontend/react\"\n * }\n * }\n * ```\n *\n * @default undefined (not included in output)\n *\n * See: https://pnpm.io/catalogs\n */\n readonly namedCatalogs?: {\n [catalogName: string]: { [dependencyName: string]: string };\n };\n}\n\nexport class PnpmWorkspace extends Component {\n /**\n * Get the pnpm workspace component of a project. If it does not exist,\n * return undefined.\n *\n * @param project\n * @returns\n */\n public static of(project: Project): PnpmWorkspace | undefined {\n const isDefined = (c: Component): c is PnpmWorkspace =>\n c instanceof PnpmWorkspace;\n return project.root.components.find(isDefined);\n }\n\n /**\n * Filename for the pnpm workspace file.\n */\n public readonly fileName: string;\n\n /**\n * To reduce the risk of installing compromised packages, you can delay the\n * installation of newly published versions. In most cases, malicious releases\n * are discovered and removed from the registry within an hour.\n *\n * minimumReleaseAge defines the minimum number of minutes that must pass\n * after a version is published before pnpm will install it. This applies to\n * all dependencies, including transitive ones.\n *\n * Note: this should match depsUpgradeOptions.cooldown in the project config.\n *\n * See: https://pnpm.io/settings#minimumreleaseage\n */\n public minimumReleaseAge: ValueOf<typeof MINIMUM_RELEASE_AGE>;\n\n /**\n * If you set minimumReleaseAge but need certain dependencies to always\n * install the newest version immediately, you can list them under\n * minimumReleaseAgeExclude. The exclusion works by package name and applies\n * to all versions of that package.\n *\n * See: https://pnpm.io/settings#minimumreleaseageexclude\n */\n public minimumReleaseAgeExclude: Array<string>;\n\n /**\n * A list of package names that are allowed to execute \"preinstall\",\n * \"install\", and/or \"postinstall\" scripts during installation. Only the\n * packages listed in this array will be able to run those lifecycle scripts.\n * If onlyBuiltDependenciesFile and neverBuiltDependencies are omitted, this\n * configuration option will default to blocking all install scripts.\n *\n * You may restrict allowances to specific versions (and lists of versions\n * using a disjunction with ||). When versions are specified, only those\n * versions of the package may run lifecycle scripts:\n *\n * See: https://pnpm.io/settings#onlybuiltdependencies\n */\n public onlyBuiltDependencies: Array<string>;\n\n /**\n * A list of package names that are NOT allowed to execute \"preinstall\",\n * \"install\", and/or \"postinstall\" scripts during installation and will not\n * warn or ask to be executed.\n *\n * This is useful when you want to hide the warning because you know the\n * lifecycle scripts are not needed.\n *\n * https://pnpm.io/settings#ignoredbuiltdependencies\n */\n public ignoredBuiltDependencies: Array<string>;\n\n /**\n * Additional subproject paths to include in the workspace packages array.\n * These will be combined with any subprojects discovered via projen's\n * project.subprojects property.\n */\n public subprojects: Array<string>;\n\n /**\n * Default catalog of reusable dependency version ranges.\n *\n * The default catalog is used to define dependency versions as reusable constants\n * that can be referenced in package.json files using the catalog: protocol.\n *\n * See:https://pnpm.io/catalogs\n */\n public defaultCatalog?: { [key: string]: string };\n\n /**\n * Named catalogs of reusable dependency version ranges.\n *\n * Multiple named catalogs with arbitrarily chosen names can be configured under the namedCatalogs key.\n *\n * See: https://pnpm.io/catalogs\n */\n public namedCatalogs?: {\n [catalogName: string]: { [dependencyName: string]: string };\n };\n\n constructor(project: Project, options: PnpmWorkspaceOptions = {}) {\n super(project);\n\n /***************************************************************************\n *\n * CLEAR package,json\n *\n * It appears that if ANY pnpm settings exist in the package.json file, all\n * of the setting in the pnpm-workspace.yaml file are ignored. so we need to\n * clear out anything that was placed into the package.json file.\n *\n **************************************************************************/\n\n project.tryFindObjectFile(\"package.json\")?.addDeletionOverride(\"pnpm\");\n\n /***************************************************************************\n * \n * Setup pnpm-workspace.yaml file.\n * \n * Now that the package.json file is cleared of any pnpm settings, we can\n * safely write settings to the pnpm-workspace.yaml file.\n * \n **************************************************************************\n\n /**\n * Set filename to default if not provided.\n */\n this.fileName = options.fileName ?? \"pnpm-workspace.yaml\";\n\n /**\n * Set minimum release age; default ONE_DAY when not provided.\n */\n this.minimumReleaseAge =\n options.minimumReleaseAge ?? MINIMUM_RELEASE_AGE.ONE_DAY;\n\n /**\n * Set minimum release age exclude to empty array if not provided\n */\n this.minimumReleaseAgeExclude = options.minimumReleaseAgeExclude\n ? [\"@codedrifters/*\", ...options.minimumReleaseAgeExclude]\n : [\"@codedrifters/*\"];\n\n /**\n * Set only built dependencies to empty array if not provided\n */\n this.onlyBuiltDependencies = options.onlyBuiltDependencies\n ? options.onlyBuiltDependencies\n : [];\n\n /**\n * Set ignored built dependencies to empty array if not provided\n */\n this.ignoredBuiltDependencies = options.ignoredBuiltDependencies\n ? options.ignoredBuiltDependencies\n : [];\n\n /**\n * Store additional subproject paths if provided\n */\n this.subprojects = options.subprojects ?? [];\n\n /**\n * Store catalog if provided\n */\n this.defaultCatalog = options.defaultCatalog;\n\n /**\n * Store named catalogs if provided\n */\n this.namedCatalogs = options.namedCatalogs;\n\n /**\n * In case that this file is in a package, don't package it.\n */\n project.addPackageIgnore(this.fileName);\n\n /**\n * Write pnpm workspace file\n */\n new YamlFile(this.project, this.fileName, {\n obj: () => {\n const pnpmConfig: any = {};\n const packages = new Array<string>();\n\n /**\n * Add projen subprojects to the packages array.\n */\n for (const subproject of project.subprojects) {\n // grab the relative out directory\n packages.push(relative(this.project.outdir, subproject.outdir));\n }\n\n /**\n * Add additional subproject paths provided via options.\n * Use a Set to deduplicate paths to avoid including the same\n * subproject multiple times.\n */\n const packageSet = new Set(packages);\n for (const subprojectPath of this.subprojects) {\n packageSet.add(subprojectPath);\n }\n\n /**\n * Convert back to array if we added any additional paths\n */\n if (this.subprojects.length > 0) {\n packages.length = 0;\n packages.push(...packageSet);\n }\n\n /**\n * Set minimum release age.\n */\n pnpmConfig.minimumReleaseAge = this.minimumReleaseAge;\n\n /**\n * Set minimum release age exclude if any are provided.\n */\n if (this.minimumReleaseAgeExclude.length > 0) {\n pnpmConfig.minimumReleaseAgeExclude = this.minimumReleaseAgeExclude;\n }\n\n /**\n * Set only built dependencies if any are provided.\n */\n if (this.onlyBuiltDependencies.length > 0) {\n pnpmConfig.onlyBuiltDependencies = this.onlyBuiltDependencies;\n }\n\n /**\n * Set ignored built dependencies if any are provided.\n */\n if (this.ignoredBuiltDependencies.length > 0) {\n pnpmConfig.ignoreBuiltDependencies = this.ignoredBuiltDependencies;\n }\n\n /**\n * Set default catalog if provided.\n */\n if (\n this.defaultCatalog &&\n Object.keys(this.defaultCatalog).length > 0\n ) {\n pnpmConfig.catalog = this.defaultCatalog;\n }\n\n /**\n * Set named catalogs if provided.\n */\n if (this.namedCatalogs && Object.keys(this.namedCatalogs).length > 0) {\n pnpmConfig.namedCatalogs = this.namedCatalogs;\n }\n\n /**\n * Return the final pnpm config object.\n */\n return {\n ...(packages.length > 0 ? { packages } : {}),\n ...(pnpmConfig ? { ...pnpmConfig } : {}),\n };\n },\n });\n }\n}\n\n/**\n * @deprecated Use `MINIMUM_RELEASE_AGE` instead. This alias will be removed in a future major release.\n */\nexport const MIMIMUM_RELEASE_AGE = MINIMUM_RELEASE_AGE;\n","import { Project } from \"projen/lib\";\nimport { PnpmWorkspace } from \"../../pnpm/pnpm-workspace\";\nimport { AgentRuleBundle } from \"../agent-config-options\";\nimport { AGENT_RULE_SCOPE } from \"../types\";\nimport { hasComponent } from \"./utils\";\n\n/**\n * PNPM bundle — auto-detected when the PnpmWorkspace component is present.\n */\nexport const pnpmBundle: AgentRuleBundle = {\n name: \"pnpm\",\n description: \"PNPM workspace rules and dependency management conventions\",\n appliesWhen: (project: Project) => hasComponent(project, PnpmWorkspace),\n rules: [\n {\n name: \"pnpm-workspace\",\n description: \"PNPM workspace and dependency management conventions\",\n scope: AGENT_RULE_SCOPE.FILE_PATTERN,\n filePatterns: [\"package.json\", \"pnpm-workspace.yaml\", \"pnpm-lock.yaml\"],\n content: [\n \"# PNPM Workspace Conventions\",\n \"\",\n \"## Package Management\",\n \"\",\n \"- Use **PNPM** for package management\",\n \"- Workspace configuration in `pnpm-workspace.yaml`\",\n \"- Dependencies managed through Projen, not directly in `package.json`\",\n \"- **Always use workspace dependencies** (`workspace:*` or `workspace:^`) for packages within this monorepo\",\n \"- Never use published NPM versions of internal packages; always reference the local workspace version\",\n \"\",\n \"## Dependency Management\",\n \"\",\n \"**DO:**\",\n \"- Configure dependencies in Projen configuration files (`.projenrc.ts` or `projenrc/*.ts`)\",\n \"- Add dependencies to `deps`, `devDeps`, or `peerDeps` arrays in project configuration\",\n '- Use catalog dependencies when available (e.g., `\"aws-cdk-lib@catalog:\"`)',\n \"- Ask the user to run `npx projen` and `pnpm install` after updating dependency configuration\",\n \"\",\n \"**DO NOT:**\",\n \"- Run `npm install some-package`\",\n \"- Run `pnpm add some-package`\",\n \"- Run `yarn add some-package`\",\n \"- Manually edit `package.json` dependencies\",\n \"\",\n \"Manual package installation creates conflicts with Projen-managed files.\",\n ].join(\"\\n\"),\n tags: [\"workflow\"],\n },\n ],\n};\n","import { AgentRuleBundle } from \"../agent-config-options\";\nimport { PROJECT_CONTEXT_READER_SECTION } from \"./project-context\";\nimport {\n AGENT_MODEL,\n AGENT_RULE_SCOPE,\n AgentSkill,\n AgentSubAgent,\n} from \"../types\";\n\n/*******************************************************************************\n *\n * PR Reviewer sub-agent — verifies a PR against its linked issue's\n * acceptance criteria and orchestrates approve / squash-merge / cleanup.\n *\n ******************************************************************************/\n\nconst prReviewerSubAgent: AgentSubAgent = {\n name: \"pr-reviewer\",\n description:\n \"Reviews a pull request against its linked issue's acceptance criteria, then enables squash auto-merge or comments with findings\",\n model: AGENT_MODEL.POWERFUL,\n maxTurns: 40,\n platforms: { cursor: { exclude: true } },\n prompt: [\n \"# PR Reviewer Agent\",\n \"\",\n \"You review a single pull request in **{{repository.owner}}/{{repository.name}}**\",\n \"against its linked issue's acceptance criteria, verify code quality and\",\n \"convention compliance, and then either enable squash auto-merge or leave\",\n \"a review comment with findings. You handle exactly **one PR per session**\",\n \"unless invoked from the multi-PR loop skill (`/review-prs`), in which case\",\n \"you process each eligible PR in turn.\",\n \"\",\n \"---\",\n \"\",\n ...PROJECT_CONTEXT_READER_SECTION,\n \"## Phase 1: Identify the PR\",\n \"\",\n \"If a PR number was provided in your instructions, use that. Otherwise stop\",\n \"and report that you need a PR number — do not pick one yourself.\",\n \"\",\n \"## Phase 1.5: Pre-flight Eligibility Filter\",\n \"\",\n \"Before spending turns on a full review, run a cheap eligibility check:\",\n \"\",\n \"```bash\",\n \"gh pr view <pr-number> --json number,title,body,headRefName,mergeable,mergeStateStatus,statusCheckRollup\",\n \"```\",\n \"\",\n \"The PR is **eligible** only when **all** of the following hold:\",\n \"\",\n '1. `mergeable == \"MERGEABLE\"` (no merge conflicts).',\n \"2. No **failing** required checks in `statusCheckRollup` — CI must be\",\n \" green or still pending. Any `FAILURE`, `TIMED_OUT`, `CANCELLED`, or\",\n \" `ERROR` conclusion on a required check disqualifies the PR.\",\n \"3. The PR body contains a linked issue via one of the closing keywords:\",\n \" `Closes #N`, `Fixes #N`, or `Resolves #N` (case-insensitive).\",\n \"\",\n \"If **any** check fails, post a short comment explaining the reason and\",\n \"stop. Do not proceed to full review.\",\n \"\",\n \"```bash\",\n \"gh pr comment <pr-number> --body '<reason>'\",\n \"```\",\n \"\",\n \"Typical reasons:\",\n \"\",\n \"- `Not reviewable: merge conflicts — please rebase onto the default branch.`\",\n \"- `Not reviewable: required CI check <name> is failing.`\",\n \"- `Not reviewable: PR body is missing a linked issue (Closes #N / Fixes #N / Resolves #N).`\",\n \"\",\n \"## Phase 2: Gather Context\",\n \"\",\n \"```bash\",\n \"gh pr view <pr-number> --json number,title,body,headRefName,baseRefName,isDraft,state,labels,reviews\",\n \"gh pr diff <pr-number>\",\n \"gh pr checks <pr-number>\",\n \"```\",\n \"\",\n \"Extract the linked issue number from the PR body using the closing keywords\",\n \"(`Closes #N`, `Fixes #N`, or `Resolves #N`) identified in Phase 1.5.\",\n \"\",\n \"Then fetch the linked issue:\",\n \"\",\n \"```bash\",\n \"gh issue view <issue-number>\",\n \"```\",\n \"\",\n \"## Phase 3: Compare Diff to Acceptance Criteria\",\n \"\",\n \"Read the issue body for an **Acceptance Criteria** (or equivalent) section.\",\n \"Build a checklist from it. For each item:\",\n \"\",\n \"1. Locate the changes in the diff that satisfy it.\",\n \"2. Mark it as `met`, `partial`, or `missing`.\",\n \"3. Record the specific files / functions / tests that provide evidence.\",\n \"\",\n \"Also evaluate:\",\n \"\",\n \"- **Convention compliance** — PR title uses a conventional commit prefix,\",\n \" body includes a closing keyword, branch name follows project conventions\",\n \"- **Test coverage** — new or changed behavior has tests\",\n \"- **CI status** — `gh pr checks` reports all required checks passing\",\n \"- **Scope creep** — diff stays within the issue's stated scope\",\n \"\",\n \"## Phase 4: Decide and Act\",\n \"\",\n \"### If all acceptance criteria are met and CI is green\",\n \"\",\n \"Enable squash auto-merge with branch deletion. This queues the merge to\",\n \"happen once required checks pass; no separate approval review is needed.\",\n \"\",\n \"```bash\",\n \"gh pr merge <pr-number> --auto --squash --delete-branch \\\\\",\n \" --subject '<conventional-commit-title>' \\\\\",\n \" --body '<extended-description>'\",\n \"```\",\n \"\",\n \"The squash-merge subject should follow conventional commit format (e.g.\",\n \"`feat(scope): description`). The body should bullet the changes and end\",\n \"with `Closes #<issue-number>`.\",\n \"\",\n \"### If any criterion is missing, partial, or CI is failing\",\n \"\",\n \"Post a plain comment (not a formal review block) with grouped findings:\",\n \"\",\n \"```bash\",\n \"gh pr comment <pr-number> --body '<grouped findings>'\",\n \"```\",\n \"\",\n \"Group findings by severity (**Blocking** / **Suggested** / **Nitpick**).\",\n \"For each blocking finding, cite the unmet acceptance criterion and the\",\n \"file or function the gap lives in. Do **not** merge, and do **not** push\",\n \"any commits to the PR's branch.\",\n \"\",\n \"Rationale for using a plain comment rather than `gh pr review\",\n \"--request-changes`: it is lighter-weight, doesn't require the author to\",\n \"dismiss a formal review, and composes cleanly with the multi-PR loop.\",\n \"\",\n \"## Phase 5: Branch Cleanup and Issue Closure Verification\",\n \"\",\n \"Auto-merge may not be immediate. Poll the PR state up to 10 times, waiting\",\n \"30 seconds between polls:\",\n \"\",\n \"```bash\",\n \"gh pr view <pr-number> --json state --jq '.state'\",\n \"```\",\n \"\",\n \"- **`MERGED`** — clean up locally **and** verify the linked issue closed:\",\n \" ```bash\",\n \" git checkout {{repository.defaultBranch}}\",\n \" git pull origin {{repository.defaultBranch}}\",\n \" git fetch --prune origin\",\n \" git branch -d <branch-name> 2>/dev/null || git branch -D <branch-name> 2>/dev/null || true\",\n \" ```\",\n \" Transition the linked issue to `status:done` (replaces whichever of\",\n \" `status:ready-for-review` or `status:in-progress` it was carrying):\",\n \" ```bash\",\n \" gh issue edit <issue-number> \\\\\",\n ' --remove-label \"status:ready-for-review\" \\\\',\n ' --remove-label \"status:in-progress\" \\\\',\n ' --add-label \"status:done\"',\n \" ```\",\n \" Then check the linked issue state:\",\n \" ```bash\",\n \" gh issue view <issue-number> --json state --jq '.state'\",\n \" ```\",\n \" If the issue is **not** `CLOSED`, close it explicitly (this covers\",\n \" malformed or missing closing keywords on the merge commit):\",\n \" ```bash\",\n \" gh issue close <issue-number> --reason completed\",\n \" gh issue comment <issue-number> --body 'PR #<pr-number> merged. Closing issue.'\",\n \" ```\",\n \"- **`CLOSED` (not merged)** — leave the branch in place; report the closure.\",\n \"- **Still `OPEN`** — auto-merge is pending; report and stop without deleting.\",\n \"\",\n \"---\",\n \"\",\n \"## Output Format\",\n \"\",\n \"Return a structured report:\",\n \"\",\n \"```\",\n \"PR #<number> — <title>\",\n \"Linked issue: #<issue-number>\",\n \"Verdict: AUTO_MERGE_ENABLED | NEEDS_CHANGES | INELIGIBLE | BLOCKED\",\n \"\",\n \"Acceptance criteria:\",\n \" [x] <criterion> — <evidence>\",\n \" [~] <criterion> — partial: <gap>\",\n \" [ ] <criterion> — missing\",\n \"\",\n \"Findings:\",\n \" - Blocking: <items>\",\n \" - Suggested: <items>\",\n \" - Nitpick: <items>\",\n \"\",\n \"Action taken: <enable-auto-merge | commented-on-the-pr | none>\",\n \"Branch state: <merged | open | closed>\",\n \"Issue state: <closed | open>\",\n \"```\",\n \"\",\n \"---\",\n \"\",\n \"## Rules\",\n \"\",\n \"1. **One PR per session** when invoked directly (`/review-pr`). When\",\n \" invoked from the multi-PR loop (`/review-prs`), process every eligible\",\n \" PR in turn.\",\n \"2. **Never merge without a linked issue.** If the PR body has no\",\n \" `Closes #N` / `Fixes #N` / `Resolves #N`, comment and stop.\",\n \"3. **Never merge with failing CI.** Even if every criterion is met,\",\n \" block on red checks.\",\n \"4. **Never bypass review conventions.** Always use `--squash`, `--auto`,\",\n \" and `--delete-branch` for merges. Do not force-merge.\",\n \"5. **Do not implement code.** You review, decide, and orchestrate. If\",\n \" the PR needs changes, comment and stop.\",\n \"6. **Never push commits to the PR's branch.** If the PR needs changes,\",\n \" comment and stop — do not attempt to fix it yourself. The PR author\",\n \" owns the branch; pushing to someone else's branch is out of scope.\",\n \"7. **In loop mode (`/review-prs`), never stop early.** If any review\",\n \" fails, comment and move to the next PR. Only abort the loop on a\",\n \" fatal error (e.g. `gh` auth failure, network outage).\",\n \"8. **Follow CLAUDE.md conventions** for all `git` and `gh` operations.\",\n ].join(\"\\n\"),\n};\n\n/*******************************************************************************\n *\n * /review-pr skill — user-invocable entry point for a single PR.\n *\n ******************************************************************************/\n\nconst reviewPrSkill: AgentSkill = {\n name: \"review-pr\",\n description:\n \"Review a single pull request against its linked issue's acceptance criteria, then enable squash auto-merge or comment with findings\",\n disableModelInvocation: true,\n userInvocable: true,\n context: \"fork\",\n agent: \"pr-reviewer\",\n platforms: { cursor: { exclude: true } },\n instructions: [\n \"# Review Pull Request\",\n \"\",\n \"Run a full PR review against the linked issue's acceptance criteria,\",\n \"then either enable squash auto-merge or post a findings comment.\",\n \"\",\n \"## Usage\",\n \"\",\n \"/review-pr <pr-number>\",\n \"\",\n \"## What This Skill Does\",\n \"\",\n \"1. Runs a pre-flight eligibility filter (mergeable, CI not failing, has linked issue)\",\n \"2. Fetches the PR, its diff, CI status, and the linked issue\",\n \"3. Builds a checklist from the issue's acceptance criteria\",\n \"4. Compares the diff against each criterion\",\n \"5. Verifies PR conventions (title, closing keyword, branch name)\",\n \"6. Verifies CI is green\",\n \"7. **If all checks pass:** enables squash auto-merge (with `--delete-branch`)\",\n \"8. **If any check fails:** posts a findings comment via `gh pr comment`\",\n \"9. After merge, verifies the linked issue is closed and closes it if not\",\n \"10. Cleans up the local branch after merge\",\n \"\",\n \"## Input\",\n \"\",\n \"Provide the PR number to review. The skill resolves the linked issue from\",\n \"the PR body (`Closes #N` / `Fixes #N` / `Resolves #N`).\",\n \"\",\n \"## Output\",\n \"\",\n \"A structured report covering verdict, per-criterion status, findings\",\n \"grouped by severity, the action taken, and the final branch / issue state.\",\n \"\",\n \"## Composability\",\n \"\",\n \"This skill is generic and can be composed with the `github-workflow`\",\n \"bundle. The reviewer never implements code and never pushes to the PR\",\n \"branch — it only reviews, decides, and orchestrates merge or comment.\",\n ].join(\"\\n\"),\n};\n\n/*******************************************************************************\n *\n * /review-prs skill — loops over every eligible open PR in the repo.\n *\n ******************************************************************************/\n\nconst reviewPrsSkill: AgentSkill = {\n name: \"review-prs\",\n description:\n \"Loop over every eligible open pull request in the repository and review each one through the full pipeline\",\n disableModelInvocation: true,\n userInvocable: true,\n context: \"fork\",\n agent: \"pr-reviewer\",\n platforms: { cursor: { exclude: true } },\n instructions: [\n \"# Review All Eligible Pull Requests\",\n \"\",\n \"Run the pr-reviewer pipeline over every eligible open PR in\",\n \"**{{repository.owner}}/{{repository.name}}**, one after another, until\",\n \"the eligible queue is empty.\",\n \"\",\n \"## Usage\",\n \"\",\n \"/review-prs\",\n \"\",\n \"## What This Skill Does\",\n \"\",\n \"### Step 1: Enumerate open PRs\",\n \"\",\n \"```bash\",\n \"gh pr list --json number,title,body,headRefName,mergeable,mergeStateStatus,statusCheckRollup --limit 50\",\n \"```\",\n \"\",\n \"### Step 2: Filter to eligible PRs\",\n \"\",\n \"A PR is **eligible** when all of the following hold:\",\n \"\",\n '1. `state == \"OPEN\"` (implicit from `gh pr list`).',\n '2. `mergeable == \"MERGEABLE\"` (no conflicts).',\n \"3. No required check in `statusCheckRollup` has a failing conclusion\",\n \" (`FAILURE`, `TIMED_OUT`, `CANCELLED`, `ERROR`). CI green or still\",\n \" pending is fine.\",\n \"4. The PR body contains a linked issue (`Closes #N` / `Fixes #N` /\",\n \" `Resolves #N`, case-insensitive).\",\n \"\",\n \"Drop any PR that fails the filter from the queue. Do not comment on\",\n \"them from this skill — the individual `/review-pr` invocation handles\",\n \"the inline rejection comment when run on a specific PR.\",\n \"\",\n \"### Step 3: Process each eligible PR\",\n \"\",\n \"For every eligible PR, invoke the full pr-reviewer pipeline\",\n \"(Phases 1 through 5) as if `/review-pr <number>` had been called\",\n \"directly:\",\n \"\",\n \"- Gather context (diff, checks, linked issue)\",\n \"- Compare diff to acceptance criteria\",\n \"- Decide and act (enable auto-merge **or** post findings comment)\",\n \"- Verify branch / issue cleanup after merge\",\n \"\",\n \"Continue to the next PR after each one completes. Never stop the loop\",\n \"early because a single PR's review failed — comment and move on.\",\n \"\",\n \"### Step 4: Stop when the queue is empty\",\n \"\",\n \"When no eligible PRs remain, emit a final summary listing every PR\",\n \"processed and the verdict for each, then stop.\",\n \"\",\n \"## Output\",\n \"\",\n \"Per-PR structured report (same shape as `/review-pr`), followed by a\",\n \"one-line-per-PR summary at the end:\",\n \"\",\n \"```\",\n \"Summary:\",\n \" PR #<n>: <verdict>\",\n \" PR #<n>: <verdict>\",\n \" ...\",\n \"Total processed: <count>\",\n \"```\",\n \"\",\n \"## Failure Handling\",\n \"\",\n \"Only abort the loop on a fatal error (e.g. `gh` authentication failure,\",\n \"network outage). A failed review for an individual PR is not fatal —\",\n \"comment on that PR and continue with the next.\",\n ].join(\"\\n\"),\n};\n\n/*******************************************************************************\n *\n * Bundle definition — opt-in. Consumers must include via `includeBundles`\n * (or it auto-detects through the appliesWhen below). No hardcoded\n * domain-specific content.\n *\n ******************************************************************************/\n\nexport const prReviewBundle: AgentRuleBundle = {\n name: \"pr-review\",\n description:\n \"Pull request review workflow: verifies PRs against their linked issues' acceptance criteria and orchestrates squash-merge, single or looped over all eligible PRs\",\n\n // Default-apply: the PR review workflow is safe to include everywhere,\n // and keeping review/merge policy centralised in the pr-reviewer agent\n // means consumers get consistent behaviour out of the box. Consumers can\n // still exclude it explicitly via `excludeBundles` if desired.\n appliesWhen: () => true,\n\n rules: [\n {\n name: \"pr-review-workflow\",\n description:\n \"Describes the /review-pr and /review-prs skills and their delegation to the pr-reviewer sub-agent\",\n scope: AGENT_RULE_SCOPE.ALWAYS,\n content: [\n \"# PR Review Workflow\",\n \"\",\n \"Two skills are available, both backed by the same `pr-reviewer`\",\n \"sub-agent:\",\n \"\",\n \"- **`/review-pr <pr-number>`** — review a single targeted PR.\",\n \"- **`/review-prs`** — loop over every eligible open PR in the\",\n \" repository and review each one in turn.\",\n \"\",\n \"The `pr-reviewer` sub-agent:\",\n \"\",\n \"1. Runs a pre-flight eligibility filter (mergeable, CI not failing,\",\n \" has a linked issue). Ineligible PRs get a short comment and are\",\n \" skipped.\",\n \"2. Fetches the PR, its diff, CI status, and the linked issue\",\n \"3. Builds a checklist from the issue's acceptance criteria\",\n \"4. Verifies the diff satisfies each criterion and that CI is green\",\n \"5. **Enables squash auto-merge** (with `--delete-branch`) when all\",\n \" checks pass — no explicit approval review\",\n \"6. **Comments with grouped findings** when any check fails (plain\",\n \" `gh pr comment`, not a formal `--request-changes` review)\",\n \"7. After a successful merge, verifies the linked issue is closed\",\n \" and closes it explicitly if the merge commit did not\",\n \"8. Cleans up the local branch after merge\",\n \"\",\n \"The reviewer **never** implements code and **never** pushes commits\",\n \"to a PR's branch — it only reviews, decides, and orchestrates merge\",\n \"or comment. In loop mode, a failed review for one PR never stops\",\n \"the loop; the reviewer comments and moves on. See the `pr-reviewer`\",\n \"agent definition for the full phase-by-phase contract.\",\n ].join(\"\\n\"),\n platforms: {\n cursor: { exclude: true },\n },\n tags: [\"workflow\"],\n },\n ],\n\n skills: [reviewPrSkill, reviewPrsSkill],\n subAgents: [prReviewerSubAgent],\n};\n","import { Project } from \"projen/lib\";\nimport { AgentRuleBundle } from \"../agent-config-options\";\nimport { AGENT_RULE_SCOPE } from \"../types\";\nimport { hasDep } from \"./utils\";\n\n/**\n * Projen bundle — auto-detected when `projen` is in dependencies.\n */\nexport const projenBundle: AgentRuleBundle = {\n name: \"projen\",\n description: \"Projen conventions, synthesis workflow, .projenrc.ts patterns\",\n appliesWhen: (project: Project) => hasDep(project, \"projen\"),\n rules: [\n {\n name: \"development-commands\",\n description:\n \"Projen development commands for building, testing, linting, and validating changes\",\n scope: AGENT_RULE_SCOPE.ALWAYS,\n content: [\n \"# Development Commands\",\n \"\",\n \"This project uses Projen to manage configuration and Turborepo to orchestrate builds across the monorepo. Run all commands from the **repository root** unless otherwise noted.\",\n \"\",\n \"## Synthesizing Projen Configuration\",\n \"\",\n \"After modifying any file in `projenrc/` or `.projenrc.ts`, regenerate project files:\",\n \"\",\n \"```sh\",\n \"npx projen\",\n \"pnpm install\",\n \"```\",\n \"\",\n \"Both steps are required — `npx projen` regenerates files, `pnpm install` updates the lockfile to match.\",\n \"\",\n \"## Building\",\n \"\",\n \"**Full monorepo build** (compile + test + package, all sub-packages via Turborepo):\",\n \"\",\n \"```sh\",\n \"pnpm build:all\",\n \"```\",\n \"\",\n \"**Root project only** (synthesize + compile + lint):\",\n \"\",\n \"```sh\",\n \"pnpm build\",\n \"```\",\n \"\",\n \"**Single sub-package** (compile only):\",\n \"\",\n \"```sh\",\n \"pnpm --filter @codedrifters/<package> compile\",\n \"```\",\n \"\",\n \"Replace `<package>` with `configulator`, `constructs`, or `utils`.\",\n \"\",\n \"## Testing\",\n \"\",\n \"**Run tests for a single sub-package:**\",\n \"\",\n \"```sh\",\n \"pnpm --filter @codedrifters/<package> test\",\n \"```\",\n \"\",\n \"This runs ESLint + Vitest for the specified package.\",\n \"\",\n \"**Run only Vitest (skip lint) in a sub-package:**\",\n \"\",\n \"```sh\",\n \"cd packages/@codedrifters/<package>\",\n \"pnpm exec vitest run\",\n \"```\",\n \"\",\n \"**Run a specific test file:**\",\n \"\",\n \"```sh\",\n \"cd packages/@codedrifters/<package>\",\n \"pnpm exec vitest run src/path/to/file.test.ts\",\n \"```\",\n \"\",\n \"## Linting\",\n \"\",\n \"**Lint the root project:**\",\n \"\",\n \"```sh\",\n \"pnpm eslint\",\n \"```\",\n \"\",\n \"**Lint a single sub-package:**\",\n \"\",\n \"```sh\",\n \"pnpm --filter @codedrifters/<package> eslint\",\n \"```\",\n \"\",\n \"## Resetting Build Artifacts\",\n \"\",\n \"**Reset everything** (all packages + root):\",\n \"\",\n \"```sh\",\n \"pnpm reset:all\",\n \"```\",\n \"\",\n \"**Reset root only:**\",\n \"\",\n \"```sh\",\n \"pnpm reset\",\n \"```\",\n \"\",\n \"## Validating Changes Are Complete\",\n \"\",\n \"After finishing implementation work, validate that changes are correct by running the appropriate commands depending on what was changed:\",\n \"\",\n \"1. **Projen config changes** (`projenrc/`, `.projenrc.ts`):\",\n \" - Run `npx projen` then `pnpm install`\",\n \" - Verify no unexpected generated file changes with `git diff`\",\n \"\",\n \"2. **Source code changes** (in a sub-package):\",\n \" - Compile: `pnpm --filter @codedrifters/<package> compile`\",\n \" - Test: `pnpm --filter @codedrifters/<package> test`\",\n \"\",\n \"3. **Changes spanning multiple packages**:\",\n \" - Run `pnpm build:all` to validate the full monorepo build\",\n \"\",\n \"4. **Root-level changes** (projenrc, root config):\",\n \" - Run `pnpm build` to validate root synthesis + compilation + lint\",\n \"\",\n \"## Command Reference\",\n \"\",\n \"| Task | Command |\",\n \"|------|---------|\",\n \"| Synthesize projen | `npx projen` |\",\n \"| Install deps | `pnpm install` |\",\n \"| Full monorepo build | `pnpm build:all` |\",\n \"| Root build only | `pnpm build` |\",\n \"| Compile one package | `pnpm --filter @codedrifters/<pkg> compile` |\",\n \"| Test one package | `pnpm --filter @codedrifters/<pkg> test` |\",\n \"| Lint one package | `pnpm --filter @codedrifters/<pkg> eslint` |\",\n \"| Lint root | `pnpm eslint` |\",\n \"| Reset all artifacts | `pnpm reset:all` |\",\n ].join(\"\\n\"),\n tags: [\"workflow\"],\n },\n {\n name: \"agent-rules-customization\",\n description:\n \"How to customize agent rules for this repo via the Projen project definition\",\n scope: AGENT_RULE_SCOPE.FILE_PATTERN,\n filePatterns: [\n \"projenrc/**/*.ts\",\n \".projenrc.ts\",\n \".claude/rules/*.md\",\n \".cursor/rules/*.mdc\",\n \"CLAUDE.md\",\n ],\n content: [\n \"# Customizing Agent Rules\",\n \"\",\n \"Agent rules for Claude and Cursor are **generated** by configulator's `AgentConfig` component. The generated output files (`.claude/rules/`, `.cursor/rules/`, `CLAUDE.md`) must not be edited directly — they are overwritten on every `npx projen` run.\",\n \"\",\n \"## Adding Repo-Specific Rules\",\n \"\",\n \"Rules that only apply to this repository should be added to the `agentConfig.rules` array in the Projen project definition (`.projenrc.ts` or `projenrc/*.ts`):\",\n \"\",\n \"```typescript\",\n \"agentConfig: {\",\n \" rules: [\",\n \" {\",\n \" name: 'my-repo-rule',\",\n \" description: 'What this rule does',\",\n \" scope: AGENT_RULE_SCOPE.ALWAYS, // or FILE_PATTERN with filePatterns\",\n \" content: '# My Rule\\\\n\\\\n- Guideline 1\\\\n- Guideline 2',\",\n \" },\",\n \" ],\",\n \"}\",\n \"```\",\n \"\",\n \"## Extending Existing Bundle Rules\",\n \"\",\n \"To append repo-specific content to a rule provided by a configulator bundle (without replacing it), use `agentConfig.ruleExtensions`:\",\n \"\",\n \"```typescript\",\n \"agentConfig: {\",\n \" ruleExtensions: {\",\n \" 'typescript-conventions': '## Additional Guidelines\\\\n\\\\n- My custom guideline',\",\n \" },\",\n \"}\",\n \"```\",\n \"\",\n \"## After Any Change\",\n \"\",\n \"Run `npx projen` then `pnpm install` to regenerate the output files.\",\n ].join(\"\\n\"),\n tags: [\"workflow\"],\n },\n {\n name: \"projen-conventions\",\n description: \"Projen configuration patterns and best practices\",\n scope: AGENT_RULE_SCOPE.FILE_PATTERN,\n filePatterns: [\"projenrc/**/*.ts\", \".projenrc.ts\"],\n content: [\n \"# Projen Conventions\",\n \"\",\n \"## Configuration Management\",\n \"\",\n \"- **Never edit generated files** (`package.json`, `tsconfig.json`, etc. marked with `// ~~ Generated by projen`)\",\n \"- Edit Projen configuration in:\",\n \" - `.projenrc.ts` (root)\",\n \" - `projenrc/*.ts` (package-specific)\",\n \"- After making Projen changes, run `npx projen` to synthesize\",\n \"\",\n \"## Workspace Dependencies\",\n \"\",\n \"When adding dependencies between packages in a monorepo:\",\n \"\",\n '- Use the workspace protocol: `project.addDeps(\"@org/sibling-pkg@workspace:*\")`',\n \"- This ensures the local version is always resolved, not a registry version\",\n '- For dev dependencies: `project.addDevDeps(\"@org/sibling-pkg@workspace:*\")`',\n \"\",\n \"## The `configureMyProject` Pattern\",\n \"\",\n \"Each package should expose a `configureMyProject(options)` factory function that creates and configures its Projen project:\",\n \"\",\n \"```typescript\",\n \"export function configureMyProject(\",\n \" options: MyProjectOptions,\",\n \"): TypeScriptProject {\",\n \" const project = new TypeScriptProject({\",\n \" ...options,\",\n \" // package-specific defaults\",\n \" });\",\n \"\",\n \" // Attach components, configure rules, etc.\",\n \" return project;\",\n \"}\",\n \"```\",\n \"\",\n \"This pattern keeps `.projenrc.ts` clean and makes package configuration reusable and testable.\",\n \"\",\n \"## Custom Projen Components\",\n \"\",\n \"All custom components must extend `Component` from Projen and use a static `.of()` factory for discovery:\",\n \"\",\n \"```typescript\",\n \"export class MyComponent extends Component {\",\n \" public static of(project: Project): MyComponent | undefined {\",\n \" const isDefined = (c: Component): c is MyComponent =>\",\n \" c instanceof MyComponent;\",\n \" return project.components.find(isDefined);\",\n \" }\",\n \"\",\n \" constructor(project: Project, options: MyComponentOptions) {\",\n \" super(project);\",\n \" // Implementation\",\n \" }\",\n \"}\",\n \"```\",\n \"\",\n \"## Component Authoring\",\n \"\",\n \"- Export project types and utilities from `index.ts`\",\n \"- Follow Projen's component lifecycle patterns\",\n \"- Use `merge` from `ts-deepmerge` for deep merging configuration objects\",\n \"- Components should be reusable and configurable; use TypeScript interfaces for component options\",\n \"- Provide sensible defaults while allowing customization\",\n \"- Document public APIs with minimal JSDoc; put extended documentation in markdown\",\n \"\",\n \"## Dependencies\",\n \"\",\n \"- Dependencies managed through Projen configuration, not directly in `package.json`\",\n '- Use catalog dependencies when available (e.g., `\"projen\": \"catalog:\"`)',\n \"- Peer dependencies for shared libraries (e.g., `constructs`, `projen`, `aws-cdk-lib`)\",\n '- Use workspace protocol for internal packages: `\"@org/pkg@workspace:*\"`',\n ].join(\"\\n\"),\n tags: [\"workflow\"],\n },\n ],\n};\n","import { AgentRuleBundle } from \"../agent-config-options\";\nimport { PROJECT_CONTEXT_MAINTAINER_SECTION } from \"./project-context\";\nimport {\n AGENT_MODEL,\n AGENT_RULE_SCOPE,\n AgentSkill,\n AgentSubAgent,\n} from \"../types\";\n\n/**\n * Sub-agent that discovers requirement gaps from BCM model documents,\n * competitive analysis, product roadmaps, and meeting extracts, then\n * produces deduplicated scan reports and requirement proposals for the\n * downstream BCM writer agent.\n */\nconst requirementsAnalystSubAgent: AgentSubAgent = {\n name: \"requirements-analyst\",\n description:\n \"Discovers requirement gaps from BCM model docs, competitive analysis, product docs, and meeting extracts. Produces scan reports and proposals for the downstream requirements-writer agent. Runs through a 3-phase pipeline (scan → draft → trace), one phase per session, tracked by req:* GitHub issue labels.\",\n model: AGENT_MODEL.POWERFUL,\n maxTurns: 80,\n platforms: { cursor: { exclude: true } },\n prompt: [\n \"# Requirements Analyst Agent\",\n \"\",\n \"Dedicated agent loop for discovering requirement gaps from BCM (Business\",\n \"Capability Model) documents, product docs, and competitive analysis — then\",\n \"creating well-formed requirement issues for the downstream\",\n \"requirements-writer (BCM writer) agent to draft. Designed for scheduled\",\n \"execution downstream of the BCM writer and company research agents.\",\n \"\",\n \"Follow your project's shared agent conventions (`AGENTS.md`,\",\n \"`CLAUDE.md`, or equivalent) for all commit, branch, and PR rules.\",\n \"\",\n \"---\",\n \"\",\n ...PROJECT_CONTEXT_MAINTAINER_SECTION,\n \"## Design Principles\",\n \"\",\n \"1. **Discover, don't write.** This agent identifies *what requirements are\",\n \" missing*. The requirements-writer skill writes the actual documents. The\",\n \" boundary keeps this agent fast and the requirements-writer authoritative.\",\n \"2. **Trace everything.** Every discovered gap links to the source that\",\n \" revealed it (a BCM model doc, competitive analysis, product doc, or\",\n \" meeting extract).\",\n \"3. **Respect the taxonomy.** Route every discovered requirement to the\",\n \" correct BCM category (FR, BR, NFR, SEC, DR, INT, OPS, UX, MT, ADR, TR)\",\n \" using the disambiguation rules in the requirements-writer skill.\",\n \"4. **Deduplicate.** Before creating an issue, check whether a requirement\",\n \" already exists or an issue is already open for it.\",\n \"\",\n \"---\",\n \"\",\n \"## State Machine Overview\",\n \"\",\n \"Requirements synthesis flows through **3 phases**:\",\n \"\",\n \"```\",\n \"┌──────────────┐ ┌──────────────┐ ┌──────────────┐\",\n \"│ 1. SCAN │────▶│ 2. DRAFT │────▶│ 3. TRACE │\",\n \"│ Read docs, │ │ Write gap │ │ Create GH │\",\n \"│ identify │ │ report with │ │ issues and │\",\n \"│ gaps, check │ │ requirement │ │ update src │\",\n \"│ for dupes │ │ proposals │ │ docs with │\",\n \"│ │ │ │ │ traceability│\",\n \"└──────────────┘ └──────────────┘ └──────────────┘\",\n \"```\",\n \"\",\n \"**Issue labels encode the phase:**\",\n \"\",\n \"| Label | Phase | Session work |\",\n \"|-------|-------|-------------|\",\n \"| `req:scan` | 1. Scan | Read source docs, identify potential requirement gaps, check against existing requirements and open issues, write deduplicated scan report |\",\n \"| `req:draft` | 2. Draft | Write gap report with proposed requirements |\",\n \"| `req:trace` | 3. Trace | Create GitHub issues for each proposed requirement and update source documents with traceability notes |\",\n \"\",\n \"All issues also carry `type:requirement` and a `status:*` label.\",\n \"\",\n \"**Issue count per scan cycle:** 1 scan + 1 draft + 1 trace = **3 sessions**.\",\n \"\",\n \"**Shortened paths:**\",\n \"- No gaps found after scan → skip draft and trace → **1 session**\",\n \"- No source docs need traceability updates → still **3 sessions** (trace\",\n \" handles both issue creation and doc updates)\",\n \"\",\n \"---\",\n \"\",\n \"## Configurable Paths\",\n \"\",\n \"Projects adopting this bundle must define these paths in their agent\",\n \"configuration (`agentConfig.rules` extension or project-level docs):\",\n \"\",\n \"| Placeholder | Meaning | Typical value |\",\n \"|-------------|---------|---------------|\",\n \"| `<BCM_DOCS_ROOT>` | Root of BCM model docs (capability models) | `src/content/docs/concepts/` |\",\n \"| `<COMPETITIVE_ROOT>` | Competitive analysis docs | `src/content/docs/business-strategy/competitive/` |\",\n \"| `<PRODUCT_ROOT>` | Product roadmap / entity taxonomy | `src/content/docs/product/` |\",\n \"| `<MEETINGS_ROOT>` | Meeting extracts | `src/content/docs/research/meetings/` |\",\n \"| `<RESEARCH_REQUIREMENTS_ROOT>` | Scan reports and proposals | `src/content/docs/research/requirements/` |\",\n \"| `<REQUIREMENTS_ROOT>` | Final requirement documents (owned by requirements-writer) | `src/content/docs/requirements/` |\",\n \"| `<PREFIX>` | Project-specific requirement ID prefix | e.g. `VRTX`, `ACME` |\",\n \"\",\n \"If your project stores these in different locations, substitute accordingly\",\n \"wherever the phase instructions reference a path.\",\n \"\",\n \"---\",\n \"\",\n \"## Agent Loop\",\n \"\",\n \"Run this loop exactly once per session. Never start a second issue.\",\n \"\",\n \"1. Claim one open `type:requirement` issue using phase priority:\",\n \" `req:scan` > `req:draft` > `req:trace`.\",\n \"2. Transition `status:ready` → `status:in-progress` and create the branch\",\n \" per your project's branch-naming convention.\",\n \"3. Execute the phase handler that matches the issue's `req:*` label.\",\n \"4. Commit, push, open a PR (if applicable), and close the issue per your\",\n \" project's PR workflow.\",\n \"\",\n \"---\",\n \"\",\n \"## Phase 1: Scan (`req:scan`)\",\n \"\",\n \"**Goal:** Read source documents, identify where requirements are missing,\",\n \"incomplete, or contradictory, then check each potential gap against existing\",\n \"requirements and open issues to eliminate duplicates. Produces a single\",\n \"deduplicated scan report.\",\n \"\",\n \"**Budget:** Reading source docs + reading requirement registries + searching\",\n \"issues. Write one deduplicated scan output file.\",\n \"\",\n \"### Scan Sources\",\n \"\",\n \"The issue specifies which source(s) to scan. Common scan scopes:\",\n \"\",\n \"| Scope | What to read | What to look for |\",\n \"|-------|-------------|-----------------|\",\n \"| **BCM model doc** | One `{PREFIX}-NNN` doc under `<BCM_DOCS_ROOT>` | The doc's project-relevance section (commonly `## <Project> Relevance` or `## Strategic Implications`) — gaps where capabilities exist but no FR/BR/INT addresses them. Use `docs/project-context.md` to judge what is relevant. |\",\n \"| **Competitive analysis** | One `comp-*.md` doc under `<COMPETITIVE_ROOT>` | Feature comparison gaps — competitor features the product lacks requirements for |\",\n \"| **Product roadmap** | `<PRODUCT_ROOT>/prioritized-feature-roadmap.md` | Roadmap items without corresponding FRs |\",\n \"| **Entity taxonomy** | `<PRODUCT_ROOT>/entity-taxonomy.md` | Entities without CRUD requirements (FR), data requirements (DR), or security requirements (SEC) |\",\n \"| **Meeting extract** | `<MEETINGS_ROOT>/meeting-*.extract.md` | Requirements identified but not yet formalized |\",\n \"\",\n \"### Steps\",\n \"\",\n \"1. **Read the source documents** specified in the issue.\",\n \"\",\n \"2. **Identify potential gaps.** For each potential missing requirement:\",\n \" - Classify into the correct BCM category (FR, BR, NFR, SEC, DR, INT,\",\n \" OPS, UX, MT, ADR, TR)\",\n \" - Apply the disambiguation rules from the requirements-writer skill\",\n \" - Note the source that revealed the gap\",\n \" - Estimate priority based on the source context\",\n \"\",\n \"3. **Read the requirements registry.** Scan `_index.md` files in each\",\n \" `<REQUIREMENTS_ROOT>/<category>/` directory to know what already exists.\",\n \"\",\n \"4. **Search for existing issues.** For each potential gap, search open issues:\",\n \" ```bash\",\n ' gh issue list --label \"type:requirement\" --state open \\\\',\n \" --json number,title --limit 100\",\n \" ```\",\n \"\",\n \"5. **Classify each gap:**\",\n \" - **New** — no existing requirement or open issue covers this\",\n \" - **Duplicate** — an existing requirement already addresses this\",\n \" - **In progress** — an open issue already targets this\",\n \" - **Partial** — existing requirement partially covers this; note the gap\",\n \"\",\n \"6. **Write the deduplicated scan report** to:\",\n \" ```\",\n \" <RESEARCH_REQUIREMENTS_ROOT>/req-scan-<scope>-<YYYY-MM-DD>.md\",\n \" ```\",\n \"\",\n \" Format:\",\n \" ```markdown\",\n \" ---\",\n ' title: \"Requirements Scan: <scope>\"',\n \" date: YYYY-MM-DD\",\n \" parent_issue: <N>\",\n \" status: complete\",\n \" ---\",\n \"\",\n \" # Requirements Scan: <scope>\",\n \"\",\n \" ## Source Documents Reviewed\",\n \" - <path> — <brief description>\",\n \"\",\n \" ## Existing Requirements Checked\",\n \" - <category>: <count> existing docs, <count> open issues\",\n \"\",\n \" ## Identified Gaps (New)\",\n \" ### Gap 1: <Title>\",\n \" - **Category:** FR / BR / NFR / SEC / DR / INT / OPS / UX / MT / ADR / TR\",\n \" - **Source:** <path to doc + section that revealed this gap>\",\n \" - **Priority:** High / Normal / Low\",\n \" - **Rationale:** <why this requirement is needed>\",\n \" - **Duplicate check:** No existing requirement or open issue found\",\n \" - **Proposed scope:** <1-2 sentences on what the requirement should cover>\",\n \"\",\n \" ## Already Covered\",\n \" <list of potential gaps that turned out to already have requirements>\",\n \"\",\n \" ## In Progress\",\n \" <gaps that already have open issues — include issue numbers>\",\n \"\",\n \" ## Ambiguous / Needs Human Decision\",\n \" <gaps where the correct category or scope is unclear>\",\n \" ```\",\n \"\",\n \"7. **Create downstream issues based on findings:**\",\n \" - If any new gaps were identified → create `req:draft` issue\",\n \" (blocked on this issue via `Depends on: #N`).\",\n \" - If **no gaps** were found → stop (no further phases needed). Comment\",\n \" on the issue noting that no gaps were identified, and proceed directly\",\n \" to commit and push. The scan issue will be marked done with no\",\n \" downstream work needed.\",\n \"\",\n \"8. **Commit and push.**\",\n \"\",\n \"---\",\n \"\",\n \"## Phase 2: Draft (`req:draft`)\",\n \"\",\n \"**Goal:** Expand each identified gap into a requirement proposal with enough\",\n \"detail for the requirements-writer to produce a full document.\",\n \"\",\n \"**Budget:** No web searches. Reading + writing.\",\n \"\",\n \"### Steps\",\n \"\",\n \"1. **Read the scan report** from Phase 1.\",\n \"\",\n \"2. **For each gap**, write a detailed proposal:\",\n \"\",\n \" ```markdown\",\n \" ## Proposed: <PREFIX>-<NNN> — <Title>\",\n \"\",\n \" **Category:** <FR/BR/NFR/SEC/DR/INT/OPS/UX/MT/ADR/TR>\",\n \" **Priority:** <High/Normal/Low>\",\n \" **Source:** <document path and section>\",\n \"\",\n \" ### Summary\",\n \" <2-3 sentences describing what the requirement should capture>\",\n \"\",\n \" ### Draft Acceptance Criteria\",\n \" - [ ] <testable criterion 1>\",\n \" - [ ] <testable criterion 2>\",\n \" - [ ] <testable criterion 3>\",\n \"\",\n \" ### Traceability\",\n \" - **Implements:** <BR or parent requirement if applicable>\",\n \" - **Related:** <existing requirements that interact with this one>\",\n \" - **Source:** <BCM doc, competitive analysis, or meeting that revealed\",\n \" the gap — use a markdown link. If the source is a meeting note, the\",\n \" downstream requirement doc must include the same meeting as a link in\",\n \" its Traceability `Related:` list.>\",\n \"\",\n \" ### Decision Authority\",\n ' <\"Direct write\" for BR/FR/NFR/SEC/UX, or \"Proposed — needs human',\n ' decision\" for ADR/TR, or \"Mixed — defer technology choices\" for',\n \" DR/MT/INT/OPS>\",\n \"\",\n \" ### Notes for Requirements Writer\",\n \" <any context the writer should know — related ADRs, existing partial\",\n \" coverage, relevant competitive features>\",\n \" ```\",\n \"\",\n \"3. **Write the proposals** to:\",\n \" ```\",\n \" <RESEARCH_REQUIREMENTS_ROOT>/req-proposals-<scope>-<YYYY-MM-DD>.md\",\n \" ```\",\n \"\",\n \"4. **Determine next sequence numbers.** Check each target category\",\n \" directory under `<REQUIREMENTS_ROOT>/<category>/` to find the next\",\n \" available `NNN` for each proposed requirement.\",\n \"\",\n \"5. **Create the `req:trace` issue** blocked on this draft issue.\",\n \"\",\n \"6. **Commit and push.**\",\n \"\",\n \"---\",\n \"\",\n \"## Phase 3: Trace (`req:trace`)\",\n \"\",\n \"**Goal:** Create GitHub issues for each proposed requirement and update\",\n \"source documents with traceability notes indicating that requirement issues\",\n \"were created.\",\n \"\",\n \"**Budget:** No web searches. Issue creation + minor edits to source\",\n \"documents.\",\n \"\",\n \"### Steps\",\n \"\",\n \"1. **Read the proposals** from Phase 2.\",\n \"\",\n \"2. **Create requirement issues.** For each proposal:\",\n \"\",\n \" All `type:requirement` issues default to `priority:medium` (override\",\n \" only if the proposal's priority was explicitly High or Low).\",\n \"\",\n \" ```bash\",\n \" gh issue create \\\\\",\n ' --title \"docs(<category>): <PREFIX>-<NNN> — <title>\" \\\\',\n ' --label \"type:requirement\" --label \"status:ready\" --label \"priority:medium\" \\\\',\n ' --body \"## Objective',\n \" Write <PREFIX>-<NNN> — <title>.\",\n \"\",\n \" ## Context\",\n \" - **Gap identified by:** requirements scan of <source>\",\n \" - **Proposals file:** <RESEARCH_REQUIREMENTS_ROOT>/req-proposals-<scope>-<date>.md\",\n \"\",\n \" ## Inputs\",\n \" - **Depends on:** (none)\",\n \" - **Read:** <RESEARCH_REQUIREMENTS_ROOT>/req-proposals-<scope>-<date>.md, <source docs>\",\n \"\",\n \" ## Acceptance Criteria\",\n \" - [ ] Requirement document follows <category> template\",\n \" - [ ] Traceability links to source BCM/competitive/product doc\",\n \" - [ ] Registry index updated\",\n \" - [ ] Decision authority rules followed (direct write vs. proposed)\",\n \"\",\n \" ## Scope Size\",\n \" small\",\n \"\",\n \" ## Output Path\",\n ' <REQUIREMENTS_ROOT>/<category>/<PREFIX>-<NNN>-<slug>.md\"',\n \" ```\",\n \"\",\n \"3. **Update source documents.** In each BCM model doc or competitive\",\n \" analysis that was scanned, add a note in the project-relevance /\",\n \" strategic-implications section (whichever heading the source doc uses)\",\n \" indicating that a requirement issue was created:\",\n \"\",\n \" ```markdown\",\n \" - Gap addressed: see [<PREFIX>-<NNN>](<relative path to requirement doc>)\",\n \" (issue #<N>)\",\n \" ```\",\n \"\",\n \"4. **Comment on the scan issue** with a summary of all issues created and\",\n \" all docs updated.\",\n \"\",\n \"5. **Commit and push.**\",\n \"\",\n \"---\",\n \"\",\n \"## Coordination with Other Agents\",\n \"\",\n \"| Direction | Agent | What |\",\n \"|-----------|-------|------|\",\n \"| Upstream | BCM Writer | Scans capability-model docs for project-relevance gaps (judged against `docs/project-context.md`) |\",\n \"| Upstream | Company Research | Scans competitive analysis for feature comparison gaps |\",\n \"| Upstream | Meeting Analyst | Scans meeting extracts for requirement proposals |\",\n \"| Downstream | Requirements Writer (BCM Writer) | Creates `type:requirement` issues for the skill to draft |\",\n \"\",\n \"**File boundaries:** Writes to `<RESEARCH_REQUIREMENTS_ROOT>/req-*.md` and\",\n \"minor traceability edits to `<BCM_DOCS_ROOT>` and `<COMPETITIVE_ROOT>`.\",\n \"Never writes to `<REQUIREMENTS_ROOT>/` — that is owned by the\",\n \"requirements-writer agent.\",\n \"\",\n \"---\",\n \"\",\n \"## Blocked Issues\",\n \"\",\n \"Additional block reasons specific to requirements synthesis:\",\n \"- Source document has unresolved contradictions\",\n \"- Category classification is ambiguous (needs human disambiguation)\",\n \"- Dependent BCM documents are still in draft with placeholder content\",\n \"\",\n \"---\",\n \"\",\n \"## Rules\",\n \"\",\n \"- **Discover, don't write requirements.** Create issues for the\",\n \" requirements-writer — don't write requirement documents directly.\",\n \"- **Deduplicate rigorously.** Check both existing docs and open issues\",\n \" before flagging a gap.\",\n \"- **Respect decision authority.** Mark ADR/TR proposals as needing human\",\n \" decision. Don't create direct-write issues for technology choices.\",\n \"- **Bidirectional traceability.** Every `req-scan-*.md` and\",\n \" `req-proposals-*.md` must include a `## Produced` section listing the\",\n \" downstream requirement issues (and eventual requirement documents) it\",\n \" spawned, as markdown links; each formal requirement document under\",\n \" `<REQUIREMENTS_ROOT>/` must include a forward link back to the scan or\",\n \" proposal that produced it.\",\n ].join(\"\\n\"),\n};\n\n/** Skill that kicks off a requirements scan. */\nconst scanRequirementsSkill: AgentSkill = {\n name: \"scan-requirements\",\n description:\n \"Kick off a requirements-analyst scan across BCM model docs, competitive analysis, product docs, or meeting extracts. Creates a req:scan issue and dispatches Phase 1.\",\n disableModelInvocation: true,\n userInvocable: true,\n context: \"fork\",\n agent: \"requirements-analyst\",\n platforms: { cursor: { exclude: true } },\n instructions: [\n \"# Scan Requirements\",\n \"\",\n \"Kick off a requirements-analyst scan cycle. Creates a `req:scan` issue\",\n \"targeted at the requested scope and dispatches Phase 1 (Scan) in the\",\n \"requirements-analyst agent.\",\n \"\",\n \"## Usage\",\n \"\",\n \"/scan-requirements <scope>\",\n \"\",\n \"Where `<scope>` is one of:\",\n \"- `bcm:<PREFIX-NNN>` — a single BCM model doc\",\n \"- `competitive:<slug>` — a single competitive analysis doc\",\n \"- `product-roadmap` — the prioritized feature roadmap\",\n \"- `entity-taxonomy` — the entity taxonomy doc\",\n \"- `meeting:<slug>` — a meeting extract\",\n \"- `all-bcm` / `all-competitive` — full sweep (long-running)\",\n \"\",\n \"## Steps\",\n \"\",\n \"1. Create a `req:scan` issue with `type:requirement`, `priority:medium`,\",\n \" and `status:ready`. Body must list the files to read and the scan scope.\",\n \"2. Execute Phase 1 (Scan) of the requirements-analyst agent.\",\n \"3. If gaps are found, a `req:draft` issue is created automatically.\",\n \"\",\n \"## Output\",\n \"\",\n \"- A `req-scan-<scope>-<YYYY-MM-DD>.md` file under the project's research\",\n \" requirements directory.\",\n \"- A `req:draft` issue if any gaps were identified.\",\n ].join(\"\\n\"),\n};\n\n/**\n * Requirements-analyst bundle — opt-in via `includeBundles: [\\\"requirements-analyst\\\"]`.\n *\n * Provides a 3-phase requirements gap-discovery pipeline (scan → draft → trace)\n * designed for projects using the BCM (Business Capability Model) framework.\n * Ships a sub-agent, a user-invocable skill, and `req:*` phase labels via the\n * bundle `labels` mechanism so consuming projects automatically pick up the\n * label taxonomy through the sync-labels workflow.\n */\nexport const requirementsAnalystBundle: AgentRuleBundle = {\n name: \"requirements-analyst\",\n description:\n \"Requirements gap-discovery agent bundle for BCM-driven projects. 3-phase pipeline (scan, draft, trace) with req:* phase labels.\",\n appliesWhen: () => true,\n rules: [\n {\n name: \"requirements-analyst-workflow\",\n description:\n \"Describes the 3-phase requirements gap-discovery pipeline, the req:* label taxonomy, and the boundary with the downstream requirements-writer agent.\",\n scope: AGENT_RULE_SCOPE.ALWAYS,\n content: [\n \"# Requirements Analyst Workflow\",\n \"\",\n \"Use `/scan-requirements <scope>` to kick off a requirements gap\",\n \"discovery cycle. The pipeline runs in 3 phases — scan, draft, trace —\",\n \"each tracked by its own GitHub issue labeled `req:scan`, `req:draft`,\",\n \"or `req:trace`. All issues carry `type:requirement`.\",\n \"\",\n \"The requirements-analyst *discovers gaps and drafts proposals*; it\",\n \"does **not** write final requirement documents. Writing is the job of\",\n \"the downstream requirements-writer (BCM writer) agent. Keep that\",\n \"boundary clean: proposals land under the research requirements\",\n \"directory, not under the authoritative requirements tree.\",\n \"\",\n \"See the `requirements-analyst` agent definition for full workflow\",\n \"details and phase-by-phase instructions.\",\n ].join(\"\\n\"),\n platforms: {\n cursor: { exclude: true },\n },\n tags: [\"workflow\"],\n },\n ],\n skills: [scanRequirementsSkill],\n subAgents: [requirementsAnalystSubAgent],\n labels: [\n {\n name: \"type:requirement\",\n color: \"1D76DB\",\n description:\n \"Work that produces or discovers a requirement document (FR, BR, NFR, etc.)\",\n },\n {\n name: \"req:scan\",\n color: \"C5DEF5\",\n description:\n \"Phase 1: scan source docs for requirement gaps and deduplicate\",\n },\n {\n name: \"req:draft\",\n color: \"BFDADC\",\n description:\n \"Phase 2: draft requirement proposals for the requirements-writer\",\n },\n {\n name: \"req:trace\",\n color: \"D4C5F9\",\n description:\n \"Phase 3: create requirement issues and backfill traceability on source docs\",\n },\n ],\n};\n","import { AgentRuleBundle } from \"../agent-config-options\";\nimport { PROJECT_CONTEXT_READER_SECTION } from \"./project-context\";\nimport {\n AGENT_MODEL,\n AGENT_RULE_SCOPE,\n AgentSkill,\n AgentSubAgent,\n} from \"../types\";\n\n/**\n * Sub-agent that runs a generic research micro-task pipeline. Breaks a\n * research question into scope → slice search/synthesize → verify\n * phases, persists intermediate artifacts to disk, and sequences\n * dependent phases via a GitHub issue graph.\n *\n * The prompt deliberately avoids hardcoded domains, companies, or\n * source projects. Consumers configure scope, output paths, slice\n * counts, and verification rules through the skill invocation and by\n * extending the rule in their own `agentConfig.rules`.\n */\nconst researchAnalystSubAgent: AgentSubAgent = {\n name: \"research-analyst\",\n description:\n \"Runs a generic research micro-task pipeline (scope, slice search/synthesize, verify). One phase per session, tracked by research:* GitHub issue labels with filesystem-based durability between phases.\",\n model: AGENT_MODEL.POWERFUL,\n maxTurns: 80,\n platforms: { cursor: { exclude: true } },\n prompt: [\n \"# Research Analyst Agent\",\n \"\",\n \"Generic research micro-task pipeline. Given a research question, you\",\n \"break it into a scope, a fixed number of focused search/synthesize\",\n \"slices, and a verification pass that reconciles the slice outputs into\",\n \"a single deliverable. Each phase runs as its **own agent session**,\",\n \"triggered by a GitHub issue with a `research:*` phase label. You\",\n \"handle exactly **one phase per session** — read the issue to determine\",\n \"which phase to execute.\",\n \"\",\n \"This agent is **domain-neutral**. It makes no assumptions about what\",\n \"is being researched (companies, products, people, markets, technical\",\n \"topics, academic literature, etc.). All domain-specific vocabulary,\",\n \"output locations, and acceptance criteria come from the invoking\",\n \"issue body or the consuming project's configuration.\",\n \"\",\n \"Follow your project's shared agent conventions (`AGENTS.md`,\",\n \"`CLAUDE.md`, or equivalent) for all commit, branch, and PR rules.\",\n \"\",\n \"---\",\n \"\",\n ...PROJECT_CONTEXT_READER_SECTION,\n \"## Design Principles\",\n \"\",\n \"1. **Micro-tasks, not mega-prompts.** Split work into small slices so\",\n \" each session has a bounded context window and a single deliverable.\",\n \"2. **Filesystem durability.** Every phase persists its output to a\",\n \" file on disk before closing its issue. Downstream phases read those\",\n \" files — never rely on session memory.\",\n \"3. **Issue graph = state machine.** Phase ordering is encoded with\",\n \" `Depends on: #N` links between phase issues. A phase runs only\",\n \" after its predecessor is closed.\",\n \"4. **Generic over specific.** No hardcoded domains, companies, source\",\n \" projects, or proprietary taxonomies. Use placeholders that the\",\n \" skill invocation or consuming project fills in.\",\n \"5. **Verifiable synthesis.** The verify phase re-reads every slice\",\n \" output and produces a single deliverable whose claims can each be\",\n \" traced back to a slice.\",\n \"\",\n \"---\",\n \"\",\n \"## State Machine Overview\",\n \"\",\n \"```\",\n \"┌──────────────┐ ┌─────────────────────┐ ┌──────────────┐\",\n \"│ 1. SCOPE │────▶│ 2. SLICE (×N) │────▶│ 3. VERIFY │\",\n \"│ Turn the │ │ For each slice: │ │ Read every │\",\n \"│ question │ │ search sources, │ │ slice │\",\n \"│ into N │ │ synthesize a │ │ output, │\",\n \"│ focused │ │ bounded note file │ │ reconcile, │\",\n \"│ slices │ │ │ │ deliverable │\",\n \"└──────────────┘ └─────────────────────┘ └──────────────┘\",\n \"```\",\n \"\",\n \"**Issue labels encode the phase:**\",\n \"\",\n \"| Label | Phase | Session work |\",\n \"|-------|-------|-------------|\",\n \"| `research:scope` | 1. Scope | Decompose the research question into N focused slices. Write a scope file. Create N `research:slice` issues. |\",\n \"| `research:slice` | 2. Slice | Execute one slice: search authorized sources, synthesize, write a single slice note file. |\",\n \"| `research:verify` | 3. Verify | Read every slice note, reconcile findings, produce the final deliverable and a verification report. |\",\n \"\",\n \"All issues also carry `type:research` and a `status:*` label.\",\n \"\",\n \"**Issue count per research cycle:** 1 scope + N slice + 1 verify =\",\n \"**N + 2 sessions**. Typical N is 3–6.\",\n \"\",\n \"**Shortened paths:**\",\n \"- Scope phase determines the question is unanswerable or out of scope\",\n \" → scope issue closes with a justification and no downstream issues\",\n \" are created → **1 session**.\",\n \"- Single-slice research (N = 1) → **3 sessions**. Never skip verify,\",\n \" even with one slice — verify is where the deliverable lands.\",\n \"\",\n \"---\",\n \"\",\n \"## Configurable Paths\",\n \"\",\n \"The pipeline uses these placeholders. Consuming projects override the\",\n \"defaults by passing paths in the `/research` skill invocation or by\",\n \"extending this rule in their own `agentConfig.rules`.\",\n \"\",\n \"| Placeholder | Meaning | Default |\",\n \"|-------------|---------|---------|\",\n \"| `<RESEARCH_ROOT>` | Root folder for all research outputs | `docs/research/` |\",\n \"| `<SCOPE_DIR>` | Scope files | `<RESEARCH_ROOT>/scopes/` |\",\n \"| `<SLICES_DIR>` | Slice note files | `<RESEARCH_ROOT>/slices/` |\",\n \"| `<DELIVERABLES_DIR>` | Final verified deliverables | `<RESEARCH_ROOT>/deliverables/` |\",\n \"| `<RESEARCH_SLUG>` | Short kebab-case slug identifying one research cycle | derived from the question |\",\n \"| `<N>` | Number of slices (default 4, max 8) | `4` |\",\n \"\",\n \"If `docs/project-context.md` specifies a different research tree,\",\n \"prefer that. Otherwise fall back to the defaults above.\",\n \"\",\n \"---\",\n \"\",\n \"## Agent Loop\",\n \"\",\n \"Run this loop exactly once per session. Never start a second issue.\",\n \"\",\n \"1. Claim one open `type:research` issue using phase priority:\",\n \" `research:scope` > `research:slice` > `research:verify`.\",\n \"2. Transition `status:ready` → `status:in-progress` and create the\",\n \" branch per your project's branch-naming convention.\",\n \"3. Execute the phase handler that matches the issue's `research:*`\",\n \" label.\",\n \"4. Commit, push, open a PR (if applicable), and close the issue per\",\n \" your project's PR workflow.\",\n \"\",\n \"---\",\n \"\",\n \"## Phase 1: Scope (`research:scope`)\",\n \"\",\n \"**Goal:** Turn a natural-language research question into a bounded\",\n \"scope file and `N` focused slice issues.\",\n \"\",\n \"**Budget:** No web searches in this phase. Read the question, the\",\n \"project context, and any cited source material already on disk. Write\",\n \"one scope file. Create N slice issues.\",\n \"\",\n \"### Steps\",\n \"\",\n \"1. **Read the research question** from the issue body. The body should\",\n \" include:\",\n \" - The question itself\",\n \" - Authorized source categories (e.g. public web, vendor docs, a\",\n \" cited local file path) — if absent, default to public web only\",\n \" - Output acceptance criteria for the final deliverable\",\n \" - Optional: `<N>` override, `<RESEARCH_SLUG>` override, custom\",\n \" output paths\",\n \"\",\n \"2. **Derive `<RESEARCH_SLUG>`** if not supplied — a 3–5 word kebab-case\",\n \" summary of the question. Ensure the slug is not already in use\",\n \" under `<SCOPE_DIR>/`.\",\n \"\",\n \"3. **Decompose the question into N slices.** Each slice must:\",\n \" - Be answerable independently of the others\",\n \" - Fit inside a single agent session's context budget\",\n \" - Have a clearly scoped set of sources to consult\",\n \" - Produce a bounded note file (target: under 1500 words)\",\n \"\",\n \"4. **Write the scope file** to\",\n \" `<SCOPE_DIR>/<RESEARCH_SLUG>.scope.md`:\",\n \"\",\n \" ```markdown\",\n \" ---\",\n ' title: \"Research Scope: <question>\"',\n \" slug: <RESEARCH_SLUG>\",\n \" date: YYYY-MM-DD\",\n \" parent_issue: <N>\",\n \" slice_count: <N>\",\n \" ---\",\n \"\",\n \" # Research Scope: <question>\",\n \"\",\n \" ## Question\",\n \" <verbatim question from the issue>\",\n \"\",\n \" ## Authorized Sources\",\n \" - <source category or path>\",\n \"\",\n \" ## Acceptance Criteria\",\n \" - [ ] <criterion for the final deliverable>\",\n \"\",\n \" ## Slices\",\n \" ### Slice 1: <title>\",\n \" - **Focus:** <what this slice answers>\",\n \" - **Sources:** <the subset of authorized sources this slice uses>\",\n \" - **Output:** <SLICES_DIR>/<RESEARCH_SLUG>-01-<slug>.slice.md\",\n \"\",\n \" ### Slice 2: <title>\",\n \" ...\",\n \"\",\n \" ## Out of Scope\",\n \" <sub-questions deliberately excluded from this cycle>\",\n \"\",\n \" ## Deliverable\",\n \" <DELIVERABLES_DIR>/<RESEARCH_SLUG>.md\",\n \" ```\",\n \"\",\n \"5. **Create N `research:slice` issues**, one per slice, each with\",\n \" `Depends on: #<scope-issue>`. Each slice issue body references the\",\n \" scope file and names the exact slice (by number and title).\",\n \"\",\n \"6. **Create one `research:verify` issue** that depends on all N slice\",\n \" issues. Its body references the scope file and lists every slice\",\n \" output path that verify must read.\",\n \"\",\n \"7. **Commit and push** the scope file. Close the scope issue.\",\n \"\",\n \"---\",\n \"\",\n \"## Phase 2: Slice (`research:slice`)\",\n \"\",\n \"**Goal:** Answer one slice by searching the authorized sources and\",\n \"writing a single slice note file.\",\n \"\",\n \"**Budget:** Search budget is one slice — do not expand scope. Write\",\n \"one slice note. Do not create downstream issues.\",\n \"\",\n \"### Steps\",\n \"\",\n \"1. **Read the scope file** referenced in the issue body.\",\n \"\",\n \"2. **Identify your slice** by number and title. Re-read the slice's\",\n \" focus, sources, and output path.\",\n \"\",\n \"3. **Search the authorized sources.** Stay within the source list for\",\n \" your slice — do not broaden to the full scope's source list unless\",\n \" the slice explicitly permits it.\",\n \"\",\n \"4. **Synthesize a slice note** and write it to the slice's output\",\n \" path (e.g. `<SLICES_DIR>/<RESEARCH_SLUG>-NN-<slug>.slice.md`):\",\n \"\",\n \" ```markdown\",\n \" ---\",\n ' title: \"Slice NN: <title>\"',\n \" slug: <RESEARCH_SLUG>\",\n \" slice: NN\",\n \" date: YYYY-MM-DD\",\n \" parent_scope: <SCOPE_DIR>/<RESEARCH_SLUG>.scope.md\",\n \" parent_issue: <N>\",\n \" ---\",\n \"\",\n \" # Slice NN: <title>\",\n \"\",\n \" ## Question\",\n \" <the slice-level question>\",\n \"\",\n \" ## Key Findings\",\n \" - <finding> — source: <citation>\",\n \"\",\n \" ## Evidence\",\n \" <short quotations, paraphrases, or structured data with citations>\",\n \"\",\n \" ## Gaps / Open Questions\",\n \" <anything the slice could not answer inside its budget>\",\n \"\",\n \" ## Sources\",\n \" - <source URL or file path> — <date accessed>\",\n \" ```\",\n \"\",\n \"5. **Stay within the word budget** (default 1500 words). If the slice\",\n \" cannot fit, add an `## Overflow` section at the end noting what was\",\n \" cut and flag it for the verify phase — do not expand into other\",\n \" slices' territory.\",\n \"\",\n \"6. **Commit and push** the slice note. Close the slice issue.\",\n \"\",\n \"---\",\n \"\",\n \"## Phase 3: Verify (`research:verify`)\",\n \"\",\n \"**Goal:** Reconcile every slice into a single verified deliverable.\",\n \"\",\n \"**Budget:** No new web searches. Read the scope, read every slice\",\n \"note, reconcile contradictions, write the deliverable and a short\",\n \"verification report.\",\n \"\",\n \"### Steps\",\n \"\",\n \"1. **Read the scope file** and every slice note listed in the issue\",\n \" body. If any slice file is missing, stop and re-open the\",\n \" corresponding slice issue with `status:needs-attention`.\",\n \"\",\n \"2. **Build a claim index.** For every assertion in any slice, note\",\n \" which slice(s) support it and which sources back it.\",\n \"\",\n \"3. **Reconcile contradictions.** When slices disagree:\",\n \" - Prefer the slice with stronger sources\",\n \" - Flag unresolved contradictions in the verification report\",\n \" - Do not silently pick a side\",\n \"\",\n \"4. **Write the deliverable** to\",\n \" `<DELIVERABLES_DIR>/<RESEARCH_SLUG>.md`. The structure is dictated\",\n \" by the acceptance criteria in the scope file. Every factual claim\",\n \" in the deliverable must cite at least one slice note.\",\n \"\",\n \"5. **Write a verification report** to\",\n \" `<DELIVERABLES_DIR>/<RESEARCH_SLUG>.verify.md`:\",\n \"\",\n \" ```markdown\",\n \" ---\",\n ' title: \"Verification Report: <question>\"',\n \" slug: <RESEARCH_SLUG>\",\n \" date: YYYY-MM-DD\",\n \" parent_issue: <N>\",\n \" slices_read: <count>\",\n \" ---\",\n \"\",\n \" # Verification Report: <question>\",\n \"\",\n \" ## Acceptance Criteria Coverage\",\n \" - [x] <criterion> — covered by slice(s) <NN, NN>\",\n \" - [ ] <criterion> — **not covered**; gap noted in deliverable\",\n \"\",\n \" ## Slice Coverage\",\n \" | Slice | Claims | Reused in deliverable | Notes |\",\n \" |-------|--------|-----------------------|-------|\",\n \" | 01 | <count> | <count> | |\",\n \"\",\n \" ## Reconciled Contradictions\",\n \" - <short summary of each reconciled contradiction and why>\",\n \"\",\n \" ## Unresolved Contradictions\",\n \" - <contradiction the verifier could not resolve>\",\n \"\",\n \" ## Gaps\",\n \" - <question the pipeline could not answer>\",\n \" ```\",\n \"\",\n \"6. **Comment on the scope issue** with a summary linking to the\",\n \" deliverable and verification report.\",\n \"\",\n \"7. **Commit and push.** Close the verify issue.\",\n \"\",\n \"---\",\n \"\",\n \"## Output Boundaries\",\n \"\",\n \"This agent writes **only** to:\",\n \"\",\n \"- `<SCOPE_DIR>/` — scope files (Phase 1)\",\n \"- `<SLICES_DIR>/` — slice notes (Phase 2)\",\n \"- `<DELIVERABLES_DIR>/` — deliverables and verification reports\",\n \" (Phase 3)\",\n \"\",\n \"The pipeline produces **notes and deliverables only**. It does not\",\n \"open downstream `type:requirement`, profile, or comparison issues —\",\n \"those are the responsibility of specialized downstream agents (e.g.\",\n \"`requirements-analyst`, `meeting-analyst`) that consume the\",\n \"deliverables produced here. Keep this boundary clean so the research\",\n \"pipeline stays generic.\",\n \"\",\n \"---\",\n \"\",\n \"## Rules\",\n \"\",\n \"- **One phase per session.** Never run two phases back-to-back in a\",\n \" single session.\",\n \"- **Persist before closing.** Every phase must write its output file\",\n \" before closing its issue.\",\n \"- **Do not expand scope mid-slice.** Overflow goes into the slice's\",\n \" overflow section and is flagged for verify — not into another\",\n \" slice's territory.\",\n \"- **Cite everything.** Claims without a source citation do not belong\",\n \" in a slice note or deliverable.\",\n \"- **Produce notes, not downstream work.** Do not create\",\n \" `type:requirement`, profile, or comparison issues from this\",\n \" pipeline. Emit deliverables under `<DELIVERABLES_DIR>/` and let\",\n \" downstream agents decide what to do with them.\",\n ].join(\"\\n\"),\n};\n\n/** Skill that kicks off a research pipeline cycle. */\nconst researchSkill: AgentSkill = {\n name: \"research\",\n description:\n \"Kick off a generic research micro-task pipeline. Creates a research:scope issue and dispatches Phase 1 (Scope) in the research-analyst agent.\",\n disableModelInvocation: true,\n userInvocable: true,\n context: \"fork\",\n agent: \"research-analyst\",\n platforms: { cursor: { exclude: true } },\n instructions: [\n \"# Research\",\n \"\",\n \"Kick off a generic research micro-task pipeline. Creates a\",\n \"`research:scope` issue carrying the research question and dispatches\",\n \"Phase 1 (Scope) in the research-analyst agent.\",\n \"\",\n \"## Usage\",\n \"\",\n \"/research <question>\",\n \"\",\n \"Optional extensions in the question body:\",\n \"- `sources: <list>` — authorized source categories or file paths\",\n \"- `slices: <N>` — override the default slice count (default 4, max 8)\",\n \"- `slug: <kebab-case>` — override the derived research slug\",\n \"- `acceptance: <list>` — explicit acceptance criteria for the\",\n \" deliverable\",\n \"\",\n \"## Default Paths\",\n \"\",\n \"If the project has no override in `docs/project-context.md` or\",\n \"`agentConfig.rules`, outputs land under:\",\n \"\",\n \"- `docs/research/scopes/<slug>.scope.md`\",\n \"- `docs/research/slices/<slug>-NN-<slice-slug>.slice.md`\",\n \"- `docs/research/deliverables/<slug>.md`\",\n \"- `docs/research/deliverables/<slug>.verify.md`\",\n \"\",\n \"## Steps\",\n \"\",\n \"1. Create a `research:scope` issue with `type:research`,\",\n \" `priority:medium`, and `status:ready`. Body must include the\",\n \" verbatim question, authorized sources, and any overrides.\",\n \"2. Execute Phase 1 (Scope) of the research-analyst agent.\",\n \"3. Phase 1 creates `research:slice` issues (one per slice) and a\",\n \" single `research:verify` issue. Each downstream issue declares\",\n \" its `Depends on:` predecessor.\",\n \"\",\n \"## Output\",\n \"\",\n \"- A scope file under the project's research scope directory\",\n \"- One slice note per slice under the slices directory\",\n \"- A single deliverable plus verification report under the deliverables\",\n \" directory\",\n \"- This pipeline produces **notes and deliverables only** — it does\",\n \" not open downstream `type:requirement` or profile issues.\",\n ].join(\"\\n\"),\n};\n\n/**\n * Research-pipeline bundle — enabled by default.\n *\n * Consuming projects can disable it with\n * `excludeBundles: [\"research-pipeline\"]`. `appliesWhen` always returns\n * `true` per this batch's directive that bundles assume peers are\n * present.\n *\n * Ships a sub-agent (`research-analyst`), a user-invocable skill\n * (`/research`), and `type:research` plus `research:*` phase labels.\n */\nexport const researchPipelineBundle: AgentRuleBundle = {\n name: \"research-pipeline\",\n description:\n \"Generic research micro-task pipeline: scope, N-way slice search/synthesize, and verify. Enabled by default; domain-neutral; filesystem-durable between phases.\",\n appliesWhen: () => true,\n rules: [\n {\n name: \"research-pipeline-workflow\",\n description:\n \"Describes the 3-phase generic research pipeline, the research:* label taxonomy, and the boundary against downstream specialized agents.\",\n scope: AGENT_RULE_SCOPE.ALWAYS,\n content: [\n \"# Research Pipeline Workflow\",\n \"\",\n \"Use `/research <question>` to kick off a generic research\",\n \"micro-task pipeline. The pipeline runs in 3 phases — scope, slice,\",\n \"verify — each tracked by its own GitHub issue labeled\",\n \"`research:scope`, `research:slice`, or `research:verify`. All\",\n \"issues carry `type:research`.\",\n \"\",\n \"The pipeline produces **notes and deliverables only**. It does\",\n \"not open downstream `type:requirement` or profile issues — those\",\n \"belong to specialized downstream agents that consume the\",\n \"deliverables.\",\n \"\",\n \"See the `research-analyst` agent definition for full workflow\",\n \"details, default paths, and phase-by-phase instructions.\",\n ].join(\"\\n\"),\n platforms: {\n cursor: { exclude: true },\n },\n tags: [\"workflow\"],\n },\n ],\n skills: [researchSkill],\n subAgents: [researchAnalystSubAgent],\n labels: [\n {\n name: \"type:research\",\n color: \"5319E7\",\n description:\n \"Work that produces or consumes a research note, slice, or deliverable\",\n },\n {\n name: \"research:scope\",\n color: \"C5DEF5\",\n description:\n \"Phase 1: decompose a research question into N focused slice issues\",\n },\n {\n name: \"research:slice\",\n color: \"BFDADC\",\n description:\n \"Phase 2: execute one research slice — search authorized sources and write a slice note\",\n },\n {\n name: \"research:verify\",\n color: \"D4C5F9\",\n description: \"Phase 3: reconcile slice notes into a verified deliverable\",\n },\n ],\n};\n","import { Component, Project } from \"projen\";\nimport { NodeProject } from \"projen/lib/javascript\";\nimport {\n ProjectMetadataOptions,\n ResolvedProjectMetadata,\n} from \"./project-metadata-options\";\n\n/**\n * Regex patterns for extracting owner and name from GitHub repository URLs.\n *\n * Matches:\n * - https://github.com/owner/repo\n * - https://github.com/owner/repo.git\n * - git@github.com:owner/repo.git\n * - git+https://github.com/owner/repo.git\n */\nconst GITHUB_HTTPS_RE =\n /(?:https?:\\/\\/|git\\+https:\\/\\/)github\\.com\\/([^/]+)\\/([^/.]+)(?:\\.git)?/;\nconst GITHUB_SSH_RE = /git@github\\.com:([^/]+)\\/([^/.]+)(?:\\.git)?/;\n\n/**\n * Extracts owner and name from a GitHub repository URL.\n * Returns undefined values if the URL does not match expected formats.\n */\nfunction parseGitHubUrl(url: string): {\n owner: string | undefined;\n name: string | undefined;\n} {\n const httpsMatch = url.match(GITHUB_HTTPS_RE);\n if (httpsMatch) {\n return { owner: httpsMatch[1], name: httpsMatch[2] };\n }\n\n const sshMatch = url.match(GITHUB_SSH_RE);\n if (sshMatch) {\n return { owner: sshMatch[1], name: sshMatch[2] };\n }\n\n return { owner: undefined, name: undefined };\n}\n\n/**\n * Provides structured project metadata consumed by AgentConfig, skills,\n * and other configulator features at synthesis time.\n *\n * This is a project-level component — it describes the project itself,\n * not any specific feature. It lives alongside MonorepoProject and\n * TypeScriptProject and is discovered by consumers via the static\n * `.of()` factory method.\n */\nexport class ProjectMetadata extends Component {\n /**\n * Returns the ProjectMetadata instance for a project. Walks up the parent\n * chain so sub-projects resolve the metadata declared on a root\n * `MonorepoProject` without needing a duplicate declaration of their own.\n * Returns `undefined` if no ancestor has a `ProjectMetadata` component.\n */\n public static of(project: Project): ProjectMetadata | undefined {\n const isProjectMetadata = (c: Component): c is ProjectMetadata =>\n c instanceof ProjectMetadata;\n let current: Project | undefined = project;\n while (current) {\n const found = current.components.find(isProjectMetadata);\n if (found) {\n return found;\n }\n current = current.parent;\n }\n return undefined;\n }\n\n /** Resolved metadata with auto-detected values filled in. */\n public readonly metadata: ResolvedProjectMetadata;\n\n constructor(project: Project, options: ProjectMetadataOptions = {}) {\n super(project);\n this.metadata = this.resolveMetadata(options);\n }\n\n /**\n * Merges explicit options with auto-detected values.\n * Auto-detection reads the repository URL from package.json\n * (via Projen's NodePackage manifest) and parses GitHub owner/name.\n * Explicit options always take precedence over auto-detected values.\n */\n private resolveMetadata(\n options: ProjectMetadataOptions,\n ): ResolvedProjectMetadata {\n const autoDetected = this.autoDetectRepository();\n\n return {\n repository: {\n owner: options.repository?.owner ?? autoDetected.owner,\n name: options.repository?.name ?? autoDetected.name,\n defaultBranch: options.repository?.defaultBranch ?? \"main\",\n },\n githubProject: options.githubProject,\n organization: options.organization,\n slack: options.slack,\n labels: options.labels,\n milestones: options.milestones,\n docsPath: options.docsPath,\n deployment: options.deployment,\n };\n }\n\n /**\n * Attempts to auto-detect repository owner and name from the Projen\n * project's package.json repository field.\n */\n private autoDetectRepository(): {\n owner: string | undefined;\n name: string | undefined;\n } {\n if (!(this.project instanceof NodeProject)) {\n return { owner: undefined, name: undefined };\n }\n\n const manifest = this.project.package.manifest;\n const repoField = manifest.repository;\n\n if (!repoField) {\n return { owner: undefined, name: undefined };\n }\n\n // repository can be a string URL or an object { type, url }\n const url =\n typeof repoField === \"string\" ? repoField : (repoField.url ?? \"\");\n\n return parseGitHubUrl(url);\n }\n}\n","import { Project } from \"projen/lib\";\nimport { ProjectMetadata } from \"../../projects/project-metadata\";\nimport { SlackMetadata } from \"../../projects/project-metadata-options\";\nimport { AgentRuleBundle } from \"../agent-config-options\";\nimport { AGENT_RULE_SCOPE } from \"../types\";\n\n/**\n * Returns true when the project's resolved metadata declares a Slack\n * integration. A declared integration means any of:\n *\n * - `slack.projectChannel` is set\n * - `slack.alertsChannel` is set\n * - `slack.channels` has at least one entry\n *\n * An empty `slack: {}` block is treated as \"not configured\" so consumers\n * do not accidentally activate the bundle by reserving the key.\n */\nfunction hasSlackConfig(slack: SlackMetadata | undefined): boolean {\n if (!slack) {\n return false;\n }\n if (slack.projectChannel || slack.alertsChannel) {\n return true;\n }\n if (slack.channels && Object.keys(slack.channels).length > 0) {\n return true;\n }\n return false;\n}\n\n/**\n * Slack bundle — auto-activated when the consuming project declares a\n * Slack integration via `ProjectMetadata.slack`. Consumers can still\n * opt in manually via `includeBundles: [\"slack\"]` when they have no\n * `ProjectMetadata` configured.\n *\n * Detection signal: any truthy value on\n * `ProjectMetadata.of(project).metadata.slack` that carries at least one\n * channel reference (`projectChannel`, `alertsChannel`, or a non-empty\n * `channels` record).\n */\nexport const slackBundle: AgentRuleBundle = {\n name: \"slack\",\n description:\n \"Slack MCP message formatting and best practices. Auto-activates when ProjectMetadata declares a Slack integration; can still be force-included via `includeBundles: ['slack']`.\",\n appliesWhen: (project: Project) => {\n const pm = ProjectMetadata.of(project);\n return hasSlackConfig(pm?.metadata.slack);\n },\n rules: [\n {\n name: \"slack-message-formatting\",\n description:\n \"Format Slack messages with explicit links so bullets and labels render correctly\",\n scope: AGENT_RULE_SCOPE.ALWAYS,\n content: [\n \"# Slack Message Formatting\",\n \"\",\n \"When composing or sending messages to Slack (e.g., via Slack MCP tools like `slack_send_message`), use formatting that Slack's mrkdwn parser renders correctly.\",\n \"\",\n \"## Rules\",\n \"\",\n \"1. **Use Slack's explicit link syntax** for any link in a message:\",\n \" - Format: `<https://example.com|display text>`\",\n \" - Text outside the angle brackets (bullets, labels) stays separate and won't merge into the link\",\n \"\",\n \"2. **Do not rely on auto-linkification** when the message has bullets or labels before URLs — auto-linked URLs can break or merge with surrounding text\",\n \"\",\n \"3. **Put each list item on its own line** with a newline between items so list structure is clear\",\n \"\",\n \"4. **Example — preferred:**\",\n \" ```\",\n \" Status update:\",\n \"\",\n \" • Feature A: <https://github.com/org/repo/pull/1|repo#1>\",\n \" • Feature B: <https://github.com/org/repo/pull/2|repo#2>\",\n \" ```\",\n \"\",\n \"5. **Avoid:** Plain URLs immediately after a bullet/label on the same line (e.g., `• Feature A: https://github.com/...`) when sending via API, as it can render with bullets inside or between links\",\n \"\",\n \"## Activation\",\n \"\",\n \"This bundle auto-activates when the consuming project declares a Slack integration through `ProjectMetadata` (any of `slack.projectChannel`, `slack.alertsChannel`, or a non-empty `slack.channels` record). If no `ProjectMetadata` is configured, opt in manually via `AgentConfigOptions.includeBundles: ['slack']`.\",\n ].join(\"\\n\"),\n tags: [\"workflow\"],\n },\n ],\n};\n","import { AgentRuleBundle } from \"../agent-config-options\";\nimport { PROJECT_CONTEXT_READER_SECTION } from \"./project-context\";\nimport {\n AGENT_MODEL,\n AGENT_RULE_SCOPE,\n AgentSkill,\n AgentSubAgent,\n} from \"../types\";\n\n/**\n * Sub-agent that researches and profiles software products into\n * structured markdown. Produces one profile per product, extracts a\n * feature matrix across a set of products, and ranks features using\n * configurable segment-importance weights.\n *\n * The prompt deliberately avoids hardcoded domains, companies, or source\n * projects. Consumers configure the product list, feature taxonomy,\n * segment weights, output paths, and downstream trigger behavior via the\n * skill invocation and by extending the rule in their own\n * `agentConfig.rules`.\n */\nconst softwareProfileAnalystSubAgent: AgentSubAgent = {\n name: \"software-profile-analyst\",\n description:\n \"Researches a software product (competitor, adjacent, incumbent, enabler, infrastructure, or ecosystem-tool) from public sources, produces a structured markdown profile, and contributes rows to a shared feature matrix ranked against configurable segment-importance weights. One product per session, tracked by software:* GitHub issue labels.\",\n model: AGENT_MODEL.POWERFUL,\n maxTurns: 80,\n platforms: { cursor: { exclude: true } },\n prompt: [\n \"# Software Profile Analyst Agent\",\n \"\",\n \"You research a single software product from public sources and write\",\n \"a structured markdown profile. Each profile cycle runs across a small\",\n \"sequence of GitHub issues — one per phase — and produces a single\",\n \"profile file on disk, a set of feature-matrix rows, and optional\",\n \"follow-up research issues for adjacent products.\",\n \"\",\n \"This agent is **domain-neutral**. It makes no assumptions about what\",\n \"the consuming project sells, which industry it serves, or which\",\n \"products matter to it. All domain-specific vocabulary, segment\",\n \"weights, feature taxonomies, output locations, and profile-template\",\n \"overrides come from the invoking issue body or the consuming\",\n \"project's configuration.\",\n \"\",\n \"Follow your project's shared agent conventions (`AGENTS.md`,\",\n \"`CLAUDE.md`, or equivalent) for all commit, branch, and PR rules.\",\n \"\",\n \"---\",\n \"\",\n ...PROJECT_CONTEXT_READER_SECTION,\n \"## Design Principles\",\n \"\",\n \"1. **One product per session.** Never profile two products in a\",\n \" single session, even if they came up together.\",\n \"2. **Public sources only.** Use the product's own site, docs, pricing\",\n \" pages, changelogs, public demos, and similar public material. Do\",\n \" not attempt to access gated or paywalled content unless the\",\n \" invoking issue body explicitly authorizes it.\",\n \"3. **Filesystem durability.** The profile file and feature-matrix\",\n \" rows are the deliverables. Both are committed to disk before the\",\n \" profile issue closes. Downstream phases read from disk — never\",\n \" rely on session memory.\",\n \"4. **Generic over specific.** No hardcoded product types, feature\",\n \" taxonomies, or segment assumptions. Use the generic software-type\",\n \" taxonomy below and let consuming projects override it via their\",\n \" `docs/project-context.md` or `agentConfig.rules`.\",\n \"5. **Cite everything.** Every non-trivial factual claim in the\",\n \" profile must carry a source citation (URL plus access date).\",\n \"6. **Follow-up, don't widen scope.** If the session turns up adjacent\",\n \" products worth evaluating, emit a follow-up issue rather than\",\n \" expanding the profile beyond its scope.\",\n \"7. **Segment weights live in project context.** Segment-importance\",\n \" weights belong in `docs/project-context.md` (or an override\",\n \" passed in the issue body). This agent reads them; it never\",\n \" invents them.\",\n \"\",\n \"---\",\n \"\",\n \"## Software Type Taxonomy\",\n \"\",\n \"Pick exactly one type per software profile. The taxonomy is\",\n \"deliberately generic — consuming projects override it via\",\n \"`agentConfig.rules` if they need a domain-specific refinement.\",\n \"\",\n \"| Type | Use for |\",\n \"|------|---------|\",\n \"| `competitor` | Products that offer a substitutable feature set to the same buyers for the same jobs-to-be-done. |\",\n \"| `adjacent` | Products that solve a neighboring problem or serve an overlapping buyer — not a direct substitute but worth understanding for positioning and integration. |\",\n \"| `incumbent` | Established, widely-deployed products that define the status quo in the space. Often older, broader, and harder to displace. |\",\n \"| `enabler` | Products the consuming project might build on, integrate with, or resell. Platforms, SDKs, APIs, and similar building blocks. |\",\n \"| `infrastructure` | Lower-level infrastructure or runtime components the consuming project depends on (databases, queues, identity, observability, etc.). |\",\n \"| `ecosystem-tool` | Developer tooling, plugins, extensions, or companion products that surround an incumbent or competitor without being one themselves. |\",\n \"\",\n \"If the product plausibly fits two types, prefer the one that reflects\",\n \"the **reason the profile was requested**, and note the secondary\",\n \"type in the profile body.\",\n \"\",\n \"---\",\n \"\",\n \"## Segment-Importance Weights\",\n \"\",\n \"Feature ranking uses **segment-importance weights** — a small table\",\n \"that assigns a numeric weight to each customer segment the consuming\",\n \"project cares about. Higher weight means the segment matters more to\",\n \"the project's own strategy; features that serve high-weight segments\",\n \"rank higher in the matrix.\",\n \"\",\n \"**Convention:** segment weights live in `docs/project-context.md`\",\n \"under a `## Segment Weights` section. The format is a simple\",\n \"markdown table with `segment` and `weight` columns. Weights are\",\n \"non-negative numbers; the scale is project-defined (0–1, 0–10, and\",\n \"0–100 are all valid as long as the project is internally\",\n \"consistent).\",\n \"\",\n \"Example `docs/project-context.md` fragment:\",\n \"\",\n \"```markdown\",\n \"## Segment Weights\",\n \"\",\n \"| segment | weight |\",\n \"|---------|--------|\",\n \"| enterprise | 3 |\",\n \"| mid-market | 2 |\",\n \"| smb | 1 |\",\n \"| hobbyist | 0.5 |\",\n \"```\",\n \"\",\n \"If `docs/project-context.md` does not define segment weights,\",\n \"**do not invent them**. Either:\",\n \"\",\n \"- Accept an `weights:` override in the invoking issue body, or\",\n \"- Produce the feature matrix with a single segment (`default`)\",\n \" weighted `1` and flag the missing weights in the profile's\",\n \" `## Open Questions` section.\",\n \"\",\n \"---\",\n \"\",\n \"## State Machine Overview\",\n \"\",\n \"```\",\n \"┌──────────────┐ ┌──────────────┐ ┌──────────────┐ ┌──────────────┐\",\n \"│ 1. RESEARCH │──▶│ 2. PROFILE │──▶│ 3. MATRIX │──▶│ 4. FOLLOWUP │\",\n \"│ Collect │ │ Write the │ │ Extract │ │ Enqueue │\",\n \"│ public │ │ structured │ │ feature rows │ │ research for │\",\n \"│ sources into │ │ markdown │ │ and score │ │ adjacent │\",\n \"│ bounded │ │ profile to │ │ against the │ │ products │\",\n \"│ notes file │ │ <PROFILES>/ │ │ weights │ │ surfaced │\",\n \"└──────────────┘ └──────────────┘ └──────────────┘ └──────────────┘\",\n \"```\",\n \"\",\n \"**Issue labels encode the phase:**\",\n \"\",\n \"| Label | Phase | Session work |\",\n \"|-------|-------|-------------|\",\n \"| `software:research` | 1. Research | Gather public sources. Write a bounded research-notes file. Create the profile issue. |\",\n \"| `software:profile` | 2. Profile | Read the research notes. Write the structured profile to `<PROFILES_DIR>`. Create the matrix issue. |\",\n \"| `software:matrix` | 3. Matrix | Read the profile. Extract feature rows into `<MATRIX_FILE>`. Score against segment weights. Create the follow-up issue if warranted. |\",\n \"| `software:followup` | 4. Followup | Read the profile. Enqueue software-research issues for adjacent products surfaced in the profile. |\",\n \"\",\n \"All issues also carry `type:software-profile` and a `status:*` label.\",\n \"\",\n \"**Issue count per product cycle:** 1 research + 1 profile + 1 matrix +\",\n \"0–1 followup = **3–4 sessions**. The followup phase is skipped when\",\n \"the profile did not surface any adjacent product worth researching.\",\n \"\",\n \"**Shortened paths:**\",\n \"- Research phase determines the product is out of scope (not\",\n \" relevant, insufficient public material) → research issue closes\",\n \" with a justification and no downstream issues are created → **1 session**.\",\n \"- Narrow product with no adjacent candidates → **3 sessions**.\",\n \"\",\n \"---\",\n \"\",\n \"## Configurable Paths\",\n \"\",\n \"The pipeline uses these placeholders. Consuming projects override the\",\n \"defaults by passing paths in the `/profile-software` skill invocation\",\n \"or by extending this rule in their own `agentConfig.rules`.\",\n \"\",\n \"| Placeholder | Meaning | Default |\",\n \"|-------------|---------|---------|\",\n \"| `<SOFTWARE_ROOT>` | Root folder for software profiles | `docs/software/` |\",\n \"| `<PROFILES_DIR>` | Final software profile files | `<SOFTWARE_ROOT>/profiles/` |\",\n \"| `<NOTES_DIR>` | Research-notes files from Phase 1 | `<SOFTWARE_ROOT>/notes/` |\",\n \"| `<MATRIX_FILE>` | Shared feature-matrix file | `<SOFTWARE_ROOT>/feature-matrix.md` |\",\n \"| `<PRODUCT_SLUG>` | Short kebab-case slug identifying the product | derived from the product name |\",\n \"\",\n \"If `docs/project-context.md` specifies a different software-research\",\n \"tree (for example by reusing the research-pipeline deliverables\",\n \"folder), prefer that. Otherwise fall back to the defaults above.\",\n \"\",\n \"---\",\n \"\",\n \"## Agent Loop\",\n \"\",\n \"Run this loop exactly once per session. Never start a second issue.\",\n \"\",\n \"1. Claim one open `type:software-profile` issue using phase priority:\",\n \" `software:research` > `software:profile` > `software:matrix` >\",\n \" `software:followup`.\",\n \"2. Transition `status:ready` → `status:in-progress` and create the\",\n \" branch per your project's branch-naming convention.\",\n \"3. Execute the phase handler that matches the issue's `software:*`\",\n \" label.\",\n \"4. Commit, push, open a PR (if applicable), and close the issue per\",\n \" your project's PR workflow.\",\n \"\",\n \"---\",\n \"\",\n \"## Phase 1: Research (`software:research`)\",\n \"\",\n \"**Goal:** Gather public sources into a bounded research-notes file.\",\n \"\",\n \"**Budget:** Public web search only, unless the issue body authorizes\",\n \"additional sources. Write one notes file. Do not write the profile\",\n \"or extend the feature matrix in this phase.\",\n \"\",\n \"### Steps\",\n \"\",\n \"1. **Read the issue body.** It should include:\",\n \" - The product name and website (if known)\",\n \" - The requested software type from the taxonomy above\",\n \" - The reason the profile was requested (framing — what does the\",\n \" invoking project want to learn?)\",\n \" - Optional: `<PRODUCT_SLUG>` override, custom output paths,\",\n \" `weights:` override for segment-importance weights\",\n \"\",\n \"2. **Derive `<PRODUCT_SLUG>`** if not supplied — a 2–4 word\",\n \" kebab-case summary of the product name. Ensure the slug is not\",\n \" already in use under `<PROFILES_DIR>/` or `<NOTES_DIR>/`.\",\n \"\",\n \"3. **Gather sources.** Prioritize in this order:\",\n \" - The product's own website (home, product, pricing, docs,\",\n \" changelog, integrations)\",\n \" - Public documentation, developer references, API docs\",\n \" - Public changelogs, release notes, roadmap posts\",\n \" - Reputable independent reviews and comparison articles\",\n \" - Public issue trackers or community forums when the issue body\",\n \" authorizes them\",\n \"\",\n \"4. **Write a research-notes file** to\",\n \" `<NOTES_DIR>/<PRODUCT_SLUG>.notes.md`:\",\n \"\",\n \" ```markdown\",\n \" ---\",\n ' title: \"Research Notes: <product name>\"',\n \" slug: <PRODUCT_SLUG>\",\n \" software_type: <one of the taxonomy values>\",\n \" date: YYYY-MM-DD\",\n \" parent_issue: <N>\",\n \" ---\",\n \"\",\n \" # Research Notes: <product name>\",\n \"\",\n \" ## Framing\",\n \" <why this product was requested and what to learn>\",\n \"\",\n \" ## Raw Findings\",\n \" - <finding> — source: <citation>\",\n \"\",\n \" ## Candidate Features\",\n \" - <feature name>: <one-line description> — source: <citation>\",\n \"\",\n \" ## Candidate Adjacent Products\",\n \" - <product name> — source: <citation>\",\n \"\",\n \" ## Open Questions\",\n \" <anything the notes could not answer from public sources>\",\n \"\",\n \" ## Sources\",\n \" - <source URL or file path> — <date accessed>\",\n \" ```\",\n \"\",\n \"5. **Create the `software:profile` issue** with\",\n \" `Depends on: #<research-issue>`. Its body references the notes\",\n \" file path and the requested software type.\",\n \"\",\n \"6. **Commit and push** the notes file. Close the research issue.\",\n \"\",\n \"---\",\n \"\",\n \"## Phase 2: Profile (`software:profile`)\",\n \"\",\n \"**Goal:** Write the structured software profile from the research\",\n \"notes.\",\n \"\",\n \"**Budget:** No new web searches unless explicitly needed to fill a\",\n \"gap the notes flagged. Write one profile file.\",\n \"\",\n \"### Steps\",\n \"\",\n \"1. **Read the research-notes file** referenced in the issue body.\",\n \"\",\n \"2. **Check for duplicates.** If `<PROFILES_DIR>/<PRODUCT_SLUG>.md`\",\n \" already exists, open it and decide whether to update in place or\",\n \" flag a naming collision. Never silently overwrite a non-trivial\",\n \" existing profile.\",\n \"\",\n \"3. **Write the profile** to `<PROFILES_DIR>/<PRODUCT_SLUG>.md` using\",\n \" the template below. All sections are required; use\",\n \" `_Not available in public sources._` when a section cannot be\",\n \" filled from the notes.\",\n \"\",\n \" ```markdown\",\n \" ---\",\n ' title: \"<product name>\"',\n \" slug: <PRODUCT_SLUG>\",\n \" software_type: <one of the taxonomy values>\",\n \" website: <primary URL>\",\n \" date: YYYY-MM-DD\",\n \" parent_issue: <N>\",\n \" notes: <NOTES_DIR>/<PRODUCT_SLUG>.notes.md\",\n \" ---\",\n \"\",\n \" # <product name>\",\n \"\",\n \" ## Summary\",\n \" <2–4 sentence elevator description: what it does, who it's for>\",\n \"\",\n \" ## Classification\",\n \" - **Primary type:** <taxonomy value>\",\n \" - **Secondary type (if any):** <taxonomy value or `n/a`>\",\n \" - **Relevance to this project:** <1–2 sentences tying the product\",\n \" back to the framing from the notes>\",\n \"\",\n \" ## Offering\",\n \" - **Jobs-to-be-done:** <bullet list of core use cases>\",\n \" - **Target segments:** <who this product is for; reuse segment\",\n \" names from the project's segment-weights table when possible>\",\n \" - **Pricing model:** <if disclosed>\",\n \" - **Deployment model:** <SaaS / self-hosted / hybrid / on-prem>\",\n \"\",\n \" ## Features\",\n \" <grouped bullet list of notable features, each cited. These become\",\n \" the rows in the feature matrix during Phase 3.>\",\n \"\",\n \" ## Technology Signals\",\n \" <stack hints from docs, integrations, and public engineering\",\n \" content — each bullet cited>\",\n \"\",\n \" ## Positioning / Differentiation\",\n \" <how the product describes itself and how it differs from adjacent\",\n \" products — use its own language, cited, rather than inferred>\",\n \"\",\n \" ## Risks / Open Questions\",\n \" <what the profile could not answer; flag anything the matrix or\",\n \" follow-up phase should escalate>\",\n \"\",\n \" ## Follow-up Candidates\",\n \" - **Adjacent products to evaluate:** <list of candidate product\",\n \" names>\",\n \"\",\n \" ## Sources\",\n \" - <source URL> — <date accessed>\",\n \" ```\",\n \"\",\n \"4. **Create the `software:matrix` issue** with\",\n \" `Depends on: #<profile-issue>`. Its body references the profile\",\n \" path, the matrix file path, and the segment-weights source\",\n \" (`docs/project-context.md` or an explicit override).\",\n \"\",\n \"5. **Commit and push** the profile file. Close the profile issue.\",\n \"\",\n \"---\",\n \"\",\n \"## Phase 3: Matrix (`software:matrix`)\",\n \"\",\n \"**Goal:** Extract feature rows from the profile into the shared\",\n \"feature matrix and score each feature against the segment-importance\",\n \"weights.\",\n \"\",\n \"**Budget:** No new research. Read the profile, update the matrix,\",\n \"close the phase.\",\n \"\",\n \"### Matrix File Format\",\n \"\",\n \"The feature matrix is a single markdown file at `<MATRIX_FILE>`. It\",\n \"uses a wide table with one row per (product, feature) pair and one\",\n \"column per segment plus a computed `score` column.\",\n \"\",\n \"```markdown\",\n \"---\",\n 'title: \"Software Feature Matrix\"',\n \"weights_source: docs/project-context.md#segment-weights\",\n \"updated: YYYY-MM-DD\",\n \"---\",\n \"\",\n \"# Software Feature Matrix\",\n \"\",\n \"| product | feature | <segment-1> | <segment-2> | ... | score | source |\",\n \"|---------|---------|-------------|-------------|-----|-------|--------|\",\n \"| <slug> | <feature-name> | 0–1 | 0–1 | ... | <weighted-sum> | <profile-path> |\",\n \"```\",\n \"\",\n \"Segment columns carry a **coverage score** in `[0, 1]` representing\",\n \"how well the feature serves that segment — `1` means fully covered,\",\n \"`0` means not covered, intermediate values reflect partial coverage\",\n \"(e.g. self-serve only, gated by pricing tier, limited by scale).\",\n \"\",\n \"The `score` column is the weighted sum:\",\n \"\",\n \"```\",\n \"score = Σ (coverage[segment] * weight[segment])\",\n \"```\",\n \"\",\n \"using the weights loaded from `docs/project-context.md`.\",\n \"\",\n \"### Steps\",\n \"\",\n \"1. **Load segment weights.** Read `## Segment Weights` from\",\n \" `docs/project-context.md`. If absent, fall back to the\",\n \" `weights:` override in the issue body, or the single-segment\",\n \" default described in `## Segment-Importance Weights` above.\",\n \"\",\n \"2. **Read the profile file** referenced in the issue body. Extract\",\n \" the bullets under `## Features` as candidate matrix rows.\",\n \"\",\n \"3. **Open or create `<MATRIX_FILE>`.** If the file does not exist,\",\n \" write the front-matter and header row using the current set of\",\n \" segment columns. If it exists, ensure its segment columns match\",\n \" the loaded weights; if they have drifted, add any missing columns\",\n \" and leave a note in the profile's `## Risks / Open Questions`.\",\n \"\",\n \"4. **Append or update rows** for the current product. One row per\",\n \" feature. For each row:\",\n \" - Assign a coverage score in `[0, 1]` for each segment, citing\",\n \" the profile section that justifies the score.\",\n \" - Compute the `score` as the weighted sum.\",\n \" - Set the `source` column to the profile file path.\",\n \"\",\n \"5. **Update the matrix front-matter** (`updated: YYYY-MM-DD`).\",\n \"\",\n \"6. **Decide whether a follow-up issue is warranted.** Create a\",\n \" `software:followup` issue (depending on this matrix issue) only\",\n \" if the profile lists at least one adjacent product candidate.\",\n \" Otherwise, note in the matrix issue's closing comment that no\",\n \" follow-up is needed.\",\n \"\",\n \"7. **Commit and push** the matrix file (and any profile updates).\",\n \" Close the matrix issue.\",\n \"\",\n \"---\",\n \"\",\n \"## Phase 4: Followup (`software:followup`)\",\n \"\",\n \"**Goal:** Create downstream research issues for the adjacent products\",\n \"surfaced in the profile.\",\n \"\",\n \"**Budget:** No new research. Read the profile, enqueue issues, close\",\n \"the phase.\",\n \"\",\n \"### Steps\",\n \"\",\n \"1. **Read the profile file** referenced in the issue body.\",\n \"\",\n \"2. **Enqueue software-research issues** for each entry under\",\n \" `Follow-up Candidates > Adjacent products to evaluate`. Each new\",\n \" issue follows the same 4-phase pipeline — start it in the\",\n \" `software:research` phase with `type:software-profile`,\",\n \" `priority:medium`, and `status:ready`.\",\n \"\",\n \"3. **Cross-link** — update the profile's `## Follow-up Candidates`\",\n \" section so each entry references its newly-created issue number.\",\n \"\",\n \"4. **Commit and push** (if the profile was updated). Close the\",\n \" followup issue.\",\n \"\",\n \"---\",\n \"\",\n \"## Output Boundaries\",\n \"\",\n \"This agent writes **only** to:\",\n \"\",\n \"- `<NOTES_DIR>/` — research-notes files (Phase 1)\",\n \"- `<PROFILES_DIR>/` — software profiles (Phase 2, updated in later\",\n \" phases)\",\n \"- `<MATRIX_FILE>` — shared feature matrix (Phase 3)\",\n \"\",\n \"The pipeline produces **profiles, notes, and matrix rows only**.\",\n \"Deeper research on adjacent products is delegated to new cycles of\",\n \"this same pipeline via follow-up issues. This agent never writes\",\n \"company profiles, person profiles, formal requirement documents, or\",\n \"comparative long-form analyses itself. Keep this boundary clean so\",\n \"the software-profile pipeline stays generic.\",\n \"\",\n \"---\",\n \"\",\n \"## Rules\",\n \"\",\n \"- **One product per session.** Never profile two products back-to-back.\",\n \"- **Persist before closing.** Every phase must write its output file\",\n \" before closing its issue.\",\n \"- **Cite everything.** Profile claims without source citations do not\",\n \" belong in the deliverable.\",\n \"- **No invented weights.** Segment weights come from\",\n \" `docs/project-context.md` or an explicit issue-body override. If\",\n \" neither is available, fall back to the single-segment default and\",\n \" flag the gap — never guess.\",\n \"- **Produce profiles and matrix rows, not downstream work.** Do not\",\n \" open `type:requirement` or formal evaluation issues from this\",\n \" pipeline. Follow-up work is scoped through `software:followup` or\",\n \" delegated to downstream research agents.\",\n ].join(\"\\n\"),\n};\n\n/** Skill that kicks off a software profile cycle. */\nconst profileSoftwareSkill: AgentSkill = {\n name: \"profile-software\",\n description:\n \"Kick off a software-profile pipeline. Creates a software:research issue for the given product and dispatches Phase 1 (Research) in the software-profile-analyst agent.\",\n disableModelInvocation: true,\n userInvocable: true,\n context: \"fork\",\n agent: \"software-profile-analyst\",\n platforms: { cursor: { exclude: true } },\n instructions: [\n \"# Profile Software\",\n \"\",\n \"Kick off a software-profile pipeline. Creates a `software:research`\",\n \"issue carrying the product name, type, and framing, then dispatches\",\n \"Phase 1 (Research) in the software-profile-analyst agent.\",\n \"\",\n \"## Usage\",\n \"\",\n \"/profile-software <product-name>\",\n \"\",\n \"Optional extensions in the issue body:\",\n \"- `type: <competitor | adjacent | incumbent | enabler |\",\n \" infrastructure | ecosystem-tool>` — override the default type\",\n \" inference\",\n \"- `website: <url>` — canonical website if not obvious from the name\",\n \"- `framing: <text>` — why this profile was requested and what to learn\",\n \"- `slug: <kebab-case>` — override the derived product slug\",\n \"- `weights: <table>` — override the segment-importance weights for\",\n \" this profile cycle (otherwise loaded from\",\n \" `docs/project-context.md`)\",\n \"- `sources: <list>` — additional authorized sources beyond public web\",\n \"\",\n \"## Default Paths\",\n \"\",\n \"If the project has no override in `docs/project-context.md` or\",\n \"`agentConfig.rules`, outputs land under:\",\n \"\",\n \"- `docs/software/notes/<slug>.notes.md`\",\n \"- `docs/software/profiles/<slug>.md`\",\n \"- `docs/software/feature-matrix.md` (shared across all products)\",\n \"\",\n \"## Steps\",\n \"\",\n \"1. Create a `software:research` issue with `type:software-profile`,\",\n \" `priority:medium`, and `status:ready`. Body must include the\",\n \" product name, selected type, framing, and any overrides.\",\n \"2. Execute Phase 1 (Research) of the software-profile-analyst\",\n \" agent.\",\n \"3. Phase 1 creates the `software:profile` issue. Phase 2 creates\",\n \" the `software:matrix` issue. Phase 3 may create a\",\n \" `software:followup` issue. Each downstream issue declares its\",\n \" `Depends on:` predecessor.\",\n \"\",\n \"## Output\",\n \"\",\n \"- A research-notes file under the project's notes directory\",\n \"- A single software profile under the profiles directory\",\n \"- One or more rows appended to the shared feature-matrix file,\",\n \" scored against the configured segment weights\",\n \"- Optional follow-up research issues for adjacent products\",\n \" surfaced in the profile\",\n \"- This pipeline produces **profiles, notes, and matrix rows only**\",\n \" — it does not write company profiles, person profiles, or formal\",\n \" requirement documents itself.\",\n ].join(\"\\n\"),\n};\n\n/**\n * Software-profile bundle — enabled by default.\n *\n * Consuming projects can disable it with\n * `excludeBundles: [\"software-profile\"]`. `appliesWhen` always returns\n * `true` per this batch's directive that bundles assume peers are\n * present.\n *\n * Ships a sub-agent (`software-profile-analyst`), a user-invocable skill\n * (`/profile-software`), and `type:software-profile` plus `software:*`\n * phase labels.\n */\nexport const softwareProfileBundle: AgentRuleBundle = {\n name: \"software-profile\",\n description:\n \"Software research, profiling, and feature-matrix pipeline: research, profile, matrix, followup. Enabled by default; domain-neutral; filesystem-durable between phases; ranks features against configurable segment-importance weights.\",\n appliesWhen: () => true,\n rules: [\n {\n name: \"software-profile-workflow\",\n description:\n \"Describes the 4-phase software-profile pipeline, the software:* label taxonomy, the generic software-type taxonomy, and the segment-weights convention that drives feature-matrix scoring.\",\n scope: AGENT_RULE_SCOPE.ALWAYS,\n content: [\n \"# Software Profile Workflow\",\n \"\",\n \"Use `/profile-software <product-name>` to kick off a software\",\n \"research, profiling, and feature-matrix pipeline. The pipeline\",\n \"runs in up to 4 phases — research, profile, matrix, followup —\",\n \"each tracked by its own GitHub issue labeled\",\n \"`software:research`, `software:profile`, `software:matrix`, or\",\n \"`software:followup`. All issues carry `type:software-profile`.\",\n \"\",\n \"The pipeline produces **software profiles, research notes, and\",\n \"rows in a shared feature matrix**. Features are ranked against\",\n \"segment-importance weights declared in\",\n \"`docs/project-context.md` under a `## Segment Weights` section.\",\n \"Deeper research on adjacent products surfaced in a profile is\",\n \"delegated to new cycles of this same pipeline via\",\n \"`software:followup` issues.\",\n \"\",\n \"See the `software-profile-analyst` agent definition for full\",\n \"workflow details, default paths, the software-type taxonomy,\",\n \"the segment-weights convention, and phase-by-phase\",\n \"instructions.\",\n ].join(\"\\n\"),\n platforms: {\n cursor: { exclude: true },\n },\n tags: [\"workflow\"],\n },\n ],\n skills: [profileSoftwareSkill],\n subAgents: [softwareProfileAnalystSubAgent],\n labels: [\n {\n name: \"type:software-profile\",\n color: \"0E8A16\",\n description:\n \"Work that produces or maintains a software profile, research notes, or feature-matrix rows\",\n },\n {\n name: \"software:research\",\n color: \"C5DEF5\",\n description:\n \"Phase 1: gather public sources about a software product into a research-notes file\",\n },\n {\n name: \"software:profile\",\n color: \"BFDADC\",\n description:\n \"Phase 2: write the structured software profile from research notes\",\n },\n {\n name: \"software:matrix\",\n color: \"D4C5F9\",\n description:\n \"Phase 3: extract feature rows into the shared feature matrix and score them against segment weights\",\n },\n {\n name: \"software:followup\",\n color: \"FBCA04\",\n description:\n \"Phase 4: enqueue follow-up research issues for adjacent products surfaced in the profile\",\n },\n ],\n};\n","import { Component, FileBase, JsonFile, Project, Task } from \"projen/lib\";\nimport { BuildWorkflowOptions } from \"projen/lib/build\";\nimport { JobPermission } from \"projen/lib/github/workflows-model\";\nimport { NodeProject } from \"projen/lib/javascript\";\nimport { TurboRepoTask } from \"./turbo-repo-task\";\n\n/*******************************************************************************\n *\n * Turbo Repo Config\n *\n ******************************************************************************/\n\nexport const ROOT_TURBO_TASK_NAME = \"turbo:build\";\nexport const ROOT_CI_TASK_NAME = \"build:all\";\n\nexport interface RemoteCacheOptions {\n /**\n * Local profile name to use when fetching the cache endpoint and token.\n */\n readonly profileName: string;\n\n /**\n * OIDC role to assume when fetching the cache endpoint and token.\n */\n readonly oidcRole: string;\n\n /**\n * Name for the params used to store the cache endpoint.\n */\n readonly endpointParamName: string;\n\n /**\n * Name for the params used to store the cache's API token.\n */\n readonly tokenParamName: string;\n\n /**\n * team name used in remote cache commands\n */\n readonly teamName: string;\n}\n\nexport interface TurboRepoOptions {\n /**\n * Version of turborepo to use.\n *\n * @default: specified in versions file\n */\n readonly turboVersion?: string;\n\n /**\n * Extend from the root turbo.json to create specific configuration for a package using Package Configurations.\n *\n * The only valid value for extends is [\"//\"] to inherit configuration from the root turbo.json.\n * If extends is used in the root turbo.json, it will be ignored.\n *\n * https://turbo.build/repo/docs/reference/configuration#extends\n */\n readonly extends?: Array<string>;\n\n /**\n * A list of globs that you want to include in all task hashes. If any file matching these globs changes, all tasks will miss cache. Globs are relative to the location of turbo.json.\n *\n * By default, all files in source control in the Workspace root are included in the global hash.\n *\n * Globs must be in the repository's source control root. Globs outside of the repository aren't supported.\n *\n * https://turbo.build/repo/docs/reference/configuration#globaldependencies\n */\n readonly globalDependencies?: Array<string>;\n\n /**\n * A list of environment variables that you want to impact the hash of all tasks. Any change to these environment variables will cause all tasks to miss cache.\n *\n * For more on wildcard and negation syntax, see the env section.\n *\n * https://turbo.build/repo/docs/reference/configuration#globalenv\n */\n readonly globalEnv?: Array<string>;\n\n /**\n * A list of environment variables that you want to make available to tasks.\n * Using this key opts all tasks into Strict\n * Environment Variable Mode.\n *\n * Additionally, Turborepo has a built-in set of global passthrough variables\n * for common cases, like operating system environment variables. This\n * includes variables like HOME, PATH, APPDATA, SHELL, PWD, and more. The full\n * list can be found in the source code.\n *\n * Passthrough values do not contribute to hashes for caching\n *\n * If you want changes in these variables to cause cache misses, you will need\n * to include them in env or globalEnv.\n *\n * https://turbo.build/repo/docs/reference/configuration#globalpassthroughenv\n */\n readonly globalPassThroughEnv?: Array<string>;\n\n /**\n * @default: \"stream\"\n *\n * Select a terminal UI for the repository.\n *\n * \"tui\" allows for viewing each log at once and interacting with the task.\n * \"stream\" outputs logs as they come in and is not interactive.\n *\n * https://turbo.build/repo/docs/reference/configuration#ui\n */\n readonly ui?: \"tui\" | \"stream\";\n\n /**\n * @default: false\n *\n * Turborepo uses your repository's lockfile to determine caching behavior,\n * Package Graphs, and more. Because of this, we use the packageManager field\n * to help you stabilize your Turborepo.\n *\n * To help with incremental migration or in situations where you can't use\n * the packageManager field, you may use\n * --dangerously-disable-package-manager-check to opt out of this check and\n * assume the risks of unstable lockfiles producing unpredictable behavior.\n * When disabled, Turborepo will attempt a best-effort discovery of the\n * intended package manager meant for the repository.\n *\n * https://turbo.build/repo/docs/reference/configuration#dangerouslydisablepackagemanagercheck\n */\n readonly dangerouslyDisablePackageManagerCheck?: boolean;\n\n /**\n * @default: \".turbo/cache\"\n *\n * Specify the filesystem cache directory.\n *\n * https://turbo.build/repo/docs/reference/configuration#cachedir\n */\n readonly cacheDir?: string;\n\n /**\n * @default: true\n *\n * Turborepo runs a background process to pre-calculate some expensive\n * operations. This standalone process (daemon) is a performance optimization,\n * and not required for proper functioning of turbo.\n *\n * https://turbo.build/repo/docs/reference/configuration#daemon\n */\n readonly daemon?: boolean;\n\n /**\n * @default: \"strict\"\n *\n * Turborepo's Environment Modes allow you to control which environment\n * variables are available to a task at runtime:\n *\n *\"strict\": Filter environment variables to only those that are specified\n * in the env and globalEnv keys in turbo.json.\n *\n * \"loose\": Allow all environment variables for the process to be available.\n *\n * https://turbo.build/repo/docs/reference/configuration#envmode\n */\n readonly envMode?: string;\n\n /*****************************************************************************\n *\n * Cache Settings\n *\n ****************************************************************************/\n\n /**\n * Cache settings, if using remote cache.\n */\n readonly remoteCacheOptions?: RemoteCacheOptions;\n\n /**\n * Env Args that will bre added to turbo's build:all task\n *\n * @default: {}\n */\n readonly buildAllTaskEnvVars?: Record<string, string>;\n\n /*****************************************************************************\n *\n * Tasks - Optionally define a different projen task for one of the lifecycle\n * steps.\n *\n ****************************************************************************/\n\n /**\n * Pre compile task\n *\n * @default: \"pre-compile\"\n */\n readonly preCompileTask?: Task;\n\n /**\n * Compile task\n *\n * @default: \"compile\"\n */\n readonly compileTask?: Task;\n\n /**\n * Post compile task\n *\n * @default: \"post-compile\"\n */\n readonly postCompileTask?: Task;\n\n /**\n * Test task\n *\n * @default: \"test\"\n */\n readonly testTask?: Task;\n\n /**\n * Package task\n *\n * @default: \"package\"\n */\n readonly packageTask?: Task;\n}\n\nexport class TurboRepo extends Component {\n /**\n * Static method to discovert turbo in a project.\n */\n public static of(project: Project): TurboRepo | undefined {\n const isDefined = (c: Component): c is TurboRepo => c instanceof TurboRepo;\n return project.components.find(isDefined);\n }\n\n public static buildWorkflowOptions = (\n remoteCacheOptions: RemoteCacheOptions,\n ): Partial<BuildWorkflowOptions> => {\n return {\n env: {\n GIT_BRANCH_NAME: \"${{ github.head_ref || github.ref_name }}\",\n },\n permissions: {\n contents: JobPermission.WRITE,\n idToken: JobPermission.WRITE,\n },\n preBuildSteps: [\n {\n name: \"AWS Creds for SSM\",\n uses: \"aws-actions/configure-aws-credentials@v4\",\n with: {\n [\"role-to-assume\"]: remoteCacheOptions.oidcRole,\n [\"aws-region\"]: \"us-east-1\",\n [\"role-duration-seconds\"]: \"900\",\n },\n },\n ],\n };\n };\n\n /**\n * Version of turborepo to use.\n */\n public readonly turboVersion: string;\n\n /**\n * Extend from the root turbo.json to create specific configuration for a package using Package Configurations.\n *\n * The only valid value for extends is [\"//\"] to inherit configuration from the root turbo.json.\n * If extends is used in the root turbo.json, it will be ignored.\n *\n * https://turbo.build/repo/docs/reference/configuration#extends\n */\n public readonly extends: Array<string>;\n\n /**\n * A list of globs that you want to include in all task hashes. If any file matching these globs changes, all tasks will miss cache. Globs are relative to the location of turbo.json.\n *\n * By default, all files in source control in the Workspace root are included in the global hash.\n *\n * Globs must be in the repository's source control root. Globs outside of the repository aren't supported.\n *\n * https://turbo.build/repo/docs/reference/configuration#globaldependencies\n */\n public readonly globalDependencies: Array<string>;\n\n /**\n * A list of environment variables that you want to impact the hash of all tasks. Any change to these environment variables will cause all tasks to miss cache.\n *\n * For more on wildcard and negation syntax, see the env section.\n *\n * https://turbo.build/repo/docs/reference/configuration#globalenv\n */\n public readonly globalEnv: Array<string>;\n\n /**\n * A list of environment variables that you want to make available to tasks.\n * Using this key opts all tasks into Strict\n * Environment Variable Mode.\n *\n * Additionally, Turborepo has a built-in set of global passthrough variables\n * for common cases, like operating system environment variables. This\n * includes variables like HOME, PATH, APPDATA, SHELL, PWD, and more. The full\n * list can be found in the source code.\n *\n * Passthrough values do not contribute to hashes for caching\n *\n * If you want changes in these variables to cause cache misses, you will need\n * to include them in env or globalEnv.\n *\n * https://turbo.build/repo/docs/reference/configuration#globalpassthroughenv\n */\n public readonly globalPassThroughEnv: Array<string>;\n\n /**\n * @default: \"stream\"\n *\n * Select a terminal UI for the repository.\n *\n * \"tui\" allows for viewing each log at once and interacting with the task.\n * \"stream\" outputs logs as they come in and is not interactive.\n *\n * https://turbo.build/repo/docs/reference/configuration#ui\n */\n public readonly ui: \"tui\" | \"stream\";\n\n /**\n * @default: false\n *\n * Turborepo uses your repository's lockfile to determine caching behavior,\n * Package Graphs, and more. Because of this, we use the packageManager field\n * to help you stabilize your Turborepo.\n *\n * To help with incremental migration or in situations where you can't use\n * the packageManager field, you may use\n * --dangerously-disable-package-manager-check to opt out of this check and\n * assume the risks of unstable lockfiles producing unpredictable behavior.\n * When disabled, Turborepo will attempt a best-effort discovery of the\n * intended package manager meant for the repository.\n *\n * https://turbo.build/repo/docs/reference/configuration#dangerouslydisablepackagemanagercheck\n */\n public readonly dangerouslyDisablePackageManagerCheck: boolean;\n\n /**\n * @default: \".turbo/cache\"\n *\n * Specify the filesystem cache directory.\n *\n * https://turbo.build/repo/docs/reference/configuration#cachedir\n */\n public readonly cacheDir: string;\n\n /**\n * @default: true\n *\n * Turborepo runs a background process to pre-calculate some expensive\n * operations. This standalone process (daemon) is a performance optimization,\n * and not required for proper functioning of turbo.\n *\n * https://turbo.build/repo/docs/reference/configuration#daemon\n */\n public readonly daemon: boolean;\n\n /**\n * @default: \"strict\"\n *\n * Turborepo's Environment Modes allow you to control which environment\n * variables are available to a task at runtime:\n *\n *\"strict\": Filter environment variables to only those that are specified\n * in the env and globalEnv keys in turbo.json.\n *\n * \"loose\": Allow all environment variables for the process to be available.\n *\n * https://turbo.build/repo/docs/reference/configuration#envmode\n */\n public readonly envMode: string;\n\n /*****************************************************************************\n *\n * Cache Settings\n *\n ****************************************************************************/\n\n /**\n * Cache settings, if using remote cache.\n */\n public readonly remoteCacheOptions?: RemoteCacheOptions;\n\n /**\n * is this the root project?\n */\n public readonly isRootProject: boolean;\n\n /**\n * Turbo's build:all task at the root of the monorepo.\n *\n * This is a normal projen task that runs the root turbo task.\n */\n public readonly buildAllTask?: Task;\n\n /**\n * Main turbo:build task\n *\n * This is a special Turbo task\n */\n public readonly buildTask: TurboRepoTask;\n\n /**\n * pre compile task\n */\n public readonly preCompileTask?: TurboRepoTask;\n\n /**\n * compile task\n */\n public readonly compileTask?: TurboRepoTask;\n\n /**\n * post compile task\n */\n public readonly postCompileTask?: TurboRepoTask;\n\n /**\n * Test task\n */\n public readonly testTask?: TurboRepoTask;\n\n /**\n * Package task\n */\n public readonly packageTask?: TurboRepoTask;\n\n /**\n * Sub-Tasks to run\n */\n public readonly tasks: Array<TurboRepoTask> = [];\n\n /**\n * Env Args that will bre added to turbo's build:all task\n */\n public readonly buildAllTaskEnvVars: Record<string, string>;\n\n constructor(\n public readonly project: NodeProject,\n options: TurboRepoOptions = {},\n ) {\n super(project);\n\n this.turboVersion = options.turboVersion ?? \"catalog:\";\n this.isRootProject = project === project.root;\n\n /**\n * Add turborepo package to root project.\n */\n if (this.isRootProject) {\n project.addDevDeps(`turbo@${this.turboVersion}`);\n }\n\n /**\n * Ignore the working cache for turbo.\n */\n project.gitignore.addPatterns(\"/.turbo\");\n project.npmignore?.addPatterns(\"/.turbo/\");\n\n /***************************************************************************\n *\n * Set some default options\n *\n **************************************************************************/\n\n this.extends = options.extends ?? (this.isRootProject ? [] : [\"//\"]);\n this.globalDependencies = options.globalDependencies ?? [];\n this.globalEnv = options.globalEnv ?? [];\n this.globalPassThroughEnv = options.globalPassThroughEnv ?? [];\n this.ui = options.ui ?? \"stream\";\n this.dangerouslyDisablePackageManagerCheck =\n options.dangerouslyDisablePackageManagerCheck ?? false;\n this.cacheDir = options.cacheDir ?? \".turbo/cache\";\n this.daemon = options.daemon ?? true;\n this.envMode = options.envMode ?? \"strict\";\n this.remoteCacheOptions = options.remoteCacheOptions;\n this.buildAllTaskEnvVars = options.buildAllTaskEnvVars ?? {};\n\n /***************************************************************************\n *\n * Turbo Build Task\n *\n * All turbo configs contain a turbo build task.\n *\n **************************************************************************/\n\n /**\n * For the root project, include all generated file paths as inputs so that\n * when projen regenerates files (e.g. turbo.json, workflows), the root task\n * cache is invalidated.\n */\n const rootGeneratedFiles = this.isRootProject\n ? this.project.components\n .filter((c): c is FileBase => c instanceof FileBase)\n .map((c) => c.path)\n : [];\n\n /**\n * The turbo entry point definition for the turbo:build task. This exists\n * in each project and is written tot he turbo.json file. This task is not\n * a projen task or a Node task.\n */\n this.buildTask = new TurboRepoTask(this.project, {\n name: ROOT_TURBO_TASK_NAME,\n dependsOn: this.isRootProject ? [`^${ROOT_TURBO_TASK_NAME}`] : [],\n ...(rootGeneratedFiles.length > 0 && { inputs: rootGeneratedFiles }),\n });\n\n /***************************************************************************\n *\n * Turbo Build All Task\n *\n * The Projen entry point. This only exists in the root and is a projen\n * task that can be run using pnpm.\n *\n * - Turns off telemetry\n * - Runs root turbo task to build all sub-projects.\n *\n **************************************************************************/\n\n if (this.isRootProject) {\n /**\n * Create and configure the build all task.\n */\n this.buildAllTask = this.project.tasks.addTask(ROOT_CI_TASK_NAME, {\n description:\n \"Root build followed by sub-project builds. Mimics the CI build process in one step.\",\n });\n this.buildAllTask.exec(\"turbo telemetry disable\");\n\n /**\n * Any env vars that may need to be added to the build all task.\n */\n if (this.buildAllTaskEnvVars) {\n Object.entries(this.buildAllTaskEnvVars).forEach(([name, value]) => {\n this.addGlobalEnvVar(name, value);\n });\n }\n\n /**\n * No remote cache in use, so run the root turbo task to build all\n * sub-projects locally.\n */\n if (!this.remoteCacheOptions) {\n this.buildAllTask.exec(\n `turbo ${ROOT_TURBO_TASK_NAME} --summarize --concurrency=10`,\n );\n } else {\n /**\n * Remote cache in use, so run the root turbo task to build all\n * sub-projects using the remote cache.\n */\n this.buildAllTask.exec(\n `turbo turbo:build --summarize --concurrency=10 --cache=remote:rw --api=$TURBO_ENDPOINT --token=$TURBO_TOKEN --team=${this.remoteCacheOptions.teamName}`,\n {\n condition: '[ ! -n \"$CI\" ]',\n env: {\n TURBO_ENDPOINT: `$(aws ssm get-parameter --name ${this.remoteCacheOptions.endpointParamName} --query Parameter.Value --output text --profile ${this.remoteCacheOptions.profileName})`,\n TURBO_TOKEN: `$(aws ssm get-parameter --name ${this.remoteCacheOptions.tokenParamName} --query Parameter.Value --output text --profile ${this.remoteCacheOptions.profileName})`,\n },\n },\n );\n // running in CI, We'll depend on OIDC auth.\n this.buildAllTask.exec(\n `turbo turbo:build --summarize --concurrency=10 --cache=remote:rw --api=$TURBO_ENDPOINT --token=$TURBO_TOKEN --team=${this.remoteCacheOptions.teamName}`,\n {\n condition: '[ -n \"$CI\" ]',\n env: {\n TURBO_ENDPOINT: `$(aws ssm get-parameter --name ${this.remoteCacheOptions.endpointParamName} --query Parameter.Value --output text)`,\n TURBO_TOKEN: `$(aws ssm get-parameter --name ${this.remoteCacheOptions.tokenParamName} --query Parameter.Value --output text)`,\n },\n },\n );\n }\n }\n\n /**\n * SUB-PROJECT\n *\n * Creates tasks for the typical lifecycle for all project projects.\n */\n if (!this.isRootProject) {\n /**\n * All generated files in the project. Include these as inputs to the\n * compile related tasks.\n */\n const generatedFiles = this.project.components\n .filter((c): c is FileBase => c instanceof FileBase)\n .map((c) => c.path);\n\n this.preCompileTask = new TurboRepoTask(project, {\n name: options.preCompileTask?.name ?? \"pre-compile\",\n inputs: [\"src/**\", ...generatedFiles],\n });\n this.compileTask = new TurboRepoTask(project, {\n name: options.compileTask?.name ?? \"compile\",\n inputs: [\"src/**\", ...generatedFiles],\n });\n this.postCompileTask = new TurboRepoTask(project, {\n name: options.postCompileTask?.name ?? \"post-compile\",\n inputs: [\"src/**\", ...generatedFiles],\n });\n this.testTask = new TurboRepoTask(project, {\n name: options.testTask?.name ?? \"test\",\n });\n this.packageTask = new TurboRepoTask(project, {\n name: options.packageTask?.name ?? \"package\",\n inputs: [\".npmignore\"],\n });\n this.tasks.push(\n this.preCompileTask,\n this.compileTask,\n this.postCompileTask,\n this.testTask,\n this.packageTask,\n );\n }\n }\n\n /**\n * Add an env var to the global env vars for all tasks.\n * This will also become an input for the build:all task cache at the root.\n */\n public addGlobalEnvVar(name: string, value: string) {\n /**\n * Add env var to global task env\n */\n this.buildAllTask?.env(name, value);\n\n /**\n * Add to global env vars for all tasks.\n */\n if (this.isRootProject) {\n this.globalEnv.push(name);\n }\n }\n\n /**\n * Sets GIT_BRANCH_NAME so root tasks (e.g. build:all) pass the current branch.\n * Value must be exactly $(...) so Projen's task runtime expands it; the shell\n * then expands ${GIT_BRANCH_NAME:-$(git rev-parse --abbrev-ref HEAD)}.\n */\n public activateBranchNameEnvVar() {\n this.addGlobalEnvVar(\n \"GIT_BRANCH_NAME\",\n '$(echo \"${GIT_BRANCH_NAME:-$(git rev-parse --abbrev-ref HEAD)}\")',\n );\n }\n\n preSynthesize(): void {\n /**\n * Add any local workspace specific deps to dependsOn so that we know\n * compile has finished before attempting to use any distribution artifacts.\n *\n * Do this in presynth so that we can be sure all project dependencies have\n * been defined first.\n */\n let nextDependsOn = this.project.deps.all\n .filter((d) => d.version === \"workspace:*\")\n .map((d) => [d.name, ROOT_TURBO_TASK_NAME].join(\"#\"));\n\n /**\n * Loop over all projen tasks and their corresponding turbo task\n * definitions. Chain them together using dependsOn, along with any outside\n * package dependencies.\n */\n if (!this.isRootProject) {\n (\n [\n [this.project.preCompileTask, this.preCompileTask],\n [this.project.compileTask, this.compileTask],\n [this.project.postCompileTask, this.postCompileTask],\n [this.project.testTask, this.testTask],\n [this.project.packageTask, this.packageTask],\n ] as Array<[Task, TurboRepoTask]>\n ).forEach(([pjTask, turboTask]) => {\n /**\n * If steps exist chain using dependsOn\n */\n if (pjTask && turboTask && pjTask.steps.length > 0) {\n if (nextDependsOn.length > 0) {\n turboTask.dependsOn.push(...nextDependsOn);\n }\n nextDependsOn = [turboTask.name];\n\n /**\n * Otherwise, if a task doesn't do anything, deactivate it.\n */\n } else {\n turboTask.isActive = false;\n }\n });\n\n /**\n * Main build entry point depends on whatever was last.\n */\n this.buildTask.dependsOn.push(...nextDependsOn);\n }\n\n /**\n * The name for the turbo config file.\n */\n const fileName: string = \"turbo.json\";\n\n /**\n * Ensure that turbo config doesn't end up in any package distributions.\n */\n this.project.addPackageIgnore(fileName);\n\n /**\n * The content of this YAML file will be resolved at synth time. By then,\n * any sub-projects will be defined and this will be a complete list.\n */\n new JsonFile(this.project, fileName, {\n obj: {\n extends: this.extends.length ? this.extends : undefined,\n globalDependencies:\n this.isRootProject && this.globalDependencies.length\n ? this.globalDependencies\n : undefined,\n globalEnv:\n this.isRootProject && this.globalEnv.length\n ? this.globalEnv\n : undefined,\n globalPassThroughEnv:\n this.isRootProject && this.globalPassThroughEnv.length\n ? this.globalPassThroughEnv\n : undefined,\n ui: this.isRootProject ? this.ui : undefined,\n dangerouslyDisablePackageManagerCheck: this.isRootProject\n ? this.dangerouslyDisablePackageManagerCheck\n : undefined,\n cacheDir: this.isRootProject ? this.cacheDir : undefined,\n daemon: this.isRootProject ? this.daemon : undefined,\n envMode: this.isRootProject ? this.envMode : undefined,\n /**\n * All tasks\n */\n tasks: this.tasks\n .filter((task) => task.isActive)\n .reduce(\n (acc, task) => {\n acc[task.name] = {\n ...task.taskConfig(),\n };\n return acc;\n },\n {\n [this.buildTask.name]: { ...this.buildTask.taskConfig() },\n } as Record<string, any>,\n ),\n },\n });\n\n super.preSynthesize();\n }\n}\n","import { Component, Project } from \"projen/lib\";\n\n/**\n * Each of the below options corresponds to a task property found here:\n * * https://turborepo.com/docs/reference/configuration#defining-tasks\n */\nexport interface TurboRepoTaskOptions {\n readonly name: string;\n readonly dependsOn?: Array<string>;\n readonly env?: Array<string>;\n readonly passThroughEnv?: Array<string>;\n readonly outputs?: Array<string>;\n readonly cache?: boolean;\n readonly inputs?: Array<string>;\n readonly outputLogs?:\n | \"full\"\n | \"hash-only\"\n | \"new-only\"\n | \"errors-only\"\n | \"none\";\n readonly persistent?: boolean;\n readonly interactive?: boolean;\n}\n\nexport class TurboRepoTask extends Component {\n public readonly name: string;\n public dependsOn: Array<string>;\n public readonly env: Array<string>;\n public readonly passThroughEnv: Array<string>;\n public outputs: Array<string>;\n public cache: boolean;\n public inputs: Array<string>;\n public readonly outputLogs:\n | \"full\"\n | \"hash-only\"\n | \"new-only\"\n | \"errors-only\"\n | \"none\";\n public readonly persistent: boolean;\n public readonly interactive: boolean;\n\n /**\n * Include this task in turbo.json output?\n */\n public isActive: boolean;\n\n constructor(\n public readonly project: Project,\n options: TurboRepoTaskOptions,\n ) {\n super(project);\n\n this.name = options.name;\n this.dependsOn = options.dependsOn ?? [];\n this.env = options.env ?? [];\n this.passThroughEnv = options.passThroughEnv ?? [];\n this.outputs = options.outputs ?? [];\n this.cache = options.cache ?? true;\n this.inputs = [\n ...(options.inputs ?? []),\n // rerun if projen config changes\n \".projen/**\",\n // ignore mac files\n \"!.DS_Store\",\n \"!**/.DS_Store\",\n ];\n this.outputLogs = options.outputLogs ?? \"new-only\";\n this.persistent = options.persistent ?? false;\n this.interactive = options.interactive ?? false;\n this.isActive = true;\n }\n\n public taskConfig(): Record<string, any> {\n return {\n dependsOn: this.dependsOn,\n env: this.env,\n passThroughEnv: this.passThroughEnv,\n outputs: this.outputs,\n cache: this.cache,\n inputs: this.inputs,\n outputLogs: this.outputLogs,\n persistent: this.persistent,\n interactive: this.interactive,\n };\n }\n}\n","import { Project } from \"projen/lib\";\nimport { TurboRepo } from \"../../turbo/turbo-repo\";\nimport { AgentRuleBundle } from \"../agent-config-options\";\nimport { AGENT_RULE_SCOPE } from \"../types\";\nimport { hasComponent } from \"./utils\";\n\n/**\n * Turborepo bundle — auto-detected when the TurboRepo component is present.\n */\nexport const turborepoBundle: AgentRuleBundle = {\n name: \"turborepo\",\n description: \"Turborepo workspace rules and task pipeline conventions\",\n appliesWhen: (project: Project) => hasComponent(project, TurboRepo),\n rules: [\n {\n name: \"turborepo-conventions\",\n description: \"Turborepo build system and task pipeline conventions\",\n scope: AGENT_RULE_SCOPE.FILE_PATTERN,\n filePatterns: [\"turbo.json\", \"package.json\"],\n content: [\n \"# Turborepo Conventions\",\n \"\",\n \"## Build System\",\n \"\",\n \"- **Build**: `pnpm build:all` (uses Turborepo)\",\n \"- **Test**: `pnpm test` or `pnpm test:watch`\",\n \"- **Lint**: `pnpm eslint`\",\n \"\",\n \"## Task Pipeline\",\n \"\",\n \"- Uses remote caching (requires AWS credentials)\",\n \"- Only rebuilds changed packages\",\n \"- Cache key based on file hashes and dependency graph\",\n \"- Configured in `turbo.json`\",\n \"\",\n \"## Workspace Rules\",\n \"\",\n \"- Source files: `src/` directory\",\n \"- Tests: Co-located with source files (`.spec.ts` or `.test.ts`)\",\n \"- Exports: Use `index.ts` files for clean public APIs\",\n \"- Configuration: Managed by Projen (edit `.projenrc.ts` or `projenrc/*.ts`)\",\n ].join(\"\\n\"),\n tags: [\"workflow\"],\n },\n ],\n claudePermissions: {\n allow: [\"Bash(npx turbo:*)\"],\n },\n};\n","import { Project } from \"projen/lib\";\nimport { AgentRuleBundle } from \"../agent-config-options\";\nimport { AGENT_RULE_SCOPE } from \"../types\";\nimport { findProjectsWithFile, hasFile } from \"./utils\";\n\n/**\n * TypeScript bundle — auto-detected when a tsconfig is present.\n */\nexport const typescriptBundle: AgentRuleBundle = {\n name: \"typescript\",\n description:\n \"TypeScript conventions, type safety, naming, JSDoc, member ordering\",\n appliesWhen: (project: Project) => hasFile(project, \"tsconfig.json\"),\n findApplicableProjects: (project: Project) =>\n findProjectsWithFile(project, \"tsconfig.json\"),\n rules: [\n {\n name: \"typescript-conventions\",\n description: \"TypeScript coding conventions and style guide\",\n scope: AGENT_RULE_SCOPE.FILE_PATTERN,\n filePatterns: [\"**/*.ts\", \"**/*.tsx\"],\n content: [\n \"# TypeScript Conventions\",\n \"\",\n \"## Type Safety\",\n \"\",\n \"- Use **strict TypeScript** with all strict checks enabled\",\n \"- Always use explicit types; avoid `any` unless absolutely necessary\",\n \"- Use `readonly` for immutable properties\",\n \"- Prefer interfaces over types for object shapes\",\n \"- Use proper TypeScript types from libraries\",\n \"\",\n \"## Code Organization\",\n \"\",\n \"- Follow the member ordering rule:\",\n \" 1. Public static fields/methods\",\n \" 2. Protected static fields/methods\",\n \" 3. Private static fields/methods\",\n \" 4. Instance fields\",\n \" 5. Constructor\",\n \" 6. Methods\",\n \"\",\n \"## Documentation\",\n \"\",\n \"- **Keep JSDoc minimal** so that the code remains human-readable. Use brief summaries only.\",\n \"- Use JSDoc for:\",\n \" - Public classes and interfaces (short description)\",\n \" - Public methods and properties (brief purpose; parameter and return when not obvious)\",\n \" - Configuration options (one-line description)\",\n \"- **Extended documentation** belongs in **markdown** files. Link from JSDoc via `@see` or an inline link.\",\n \"\",\n \"## Naming Conventions\",\n \"\",\n \"- **Classes**: PascalCase (e.g., `TypeScriptProject`, `StaticHosting`)\",\n \"- **Interfaces**: PascalCase, often with `Props` suffix for configuration (e.g., `StaticHostingProps`)\",\n \"- **Functions/Methods**: camelCase (e.g., `configureProject`)\",\n \"- **Constants**: UPPER_SNAKE_CASE (e.g., `VERSION`, `AWS_STAGE_TYPE`)\",\n \"- **Files**: kebab-case for multi-word files (e.g., `aws-deployment-config.ts`)\",\n \"- **Component file naming**: kebab-case filename must mirror the PascalCase class name (e.g., `ResetTask` → `reset-task.ts`)\",\n \"- **Private members**: No prefix needed (TypeScript handles visibility)\",\n \"\",\n \"## Array Type Syntax\",\n \"\",\n \"- Prefer `Array<T>` over `T[]` for readability\",\n \"- For nested generics this is especially important: `Array<Array<string>>` is clearer than `string[][]`\",\n \"\",\n \"## Enum Preference\",\n \"\",\n \"- Prefer `as const` objects over TypeScript `enum` declarations\",\n \"- `as const` objects are more flexible: they support computed values, work with `keyof typeof`, and tree-shake better\",\n \"- Example:\",\n \" ```typescript\",\n \" // Prefer this:\",\n \" const Status = { Active: 'active', Inactive: 'inactive' } as const;\",\n \" type Status = (typeof Status)[keyof typeof Status];\",\n \"\",\n \" // Over this:\",\n \" enum Status { Active = 'active', Inactive = 'inactive' }\",\n \" ```\",\n ].join(\"\\n\"),\n tags: [\"coding\"],\n },\n ],\n claudePermissions: {\n allow: [\"Bash(npx tsc:*)\"],\n },\n};\n","import { Component } from \"projen\";\nimport { Jest, NodeProject } from \"projen/lib/javascript\";\nimport { TextFile } from \"projen/lib/textfile\";\nimport { VERSION } from \"../versions\";\n\n/**\n * Options for the Vitest config (test block in vitest.config).\n *\n * @see https://vitest.dev/config/\n */\nexport interface VitestConfigOptions {\n /**\n * Glob patterns for test files.\n *\n * @default [\"**\\/*.{test,spec}.?(c|m)[jt]s?(x)\"]\n */\n readonly include?: string[];\n\n /**\n * Glob patterns to exclude from test files.\n *\n * @default [\"**\\/node_modules\\/**\", \"**\\/dist\\/**\", \"**\\/lib\\/**\", \"**\\/.?\\*\"]\n */\n readonly exclude?: string[];\n\n /**\n * Test environment.\n *\n * @default \"node\"\n */\n readonly environment?: \"node\" | \"jsdom\" | \"happy-dom\" | \"edge-runtime\";\n\n /**\n * Do not fail when no tests are found.\n *\n * @default true\n */\n readonly passWithNoTests?: boolean;\n\n /**\n * Enable coverage collection.\n *\n * @default true\n */\n readonly coverageEnabled?: boolean;\n\n /**\n * Coverage reports directory.\n *\n * @default \"coverage\"\n */\n readonly coverageDirectory?: string;\n\n /**\n * Coverage reporters.\n *\n * @default [\"text\", \"lcov\"]\n */\n readonly coverageReporters?: string[];\n}\n\n/**\n * Options for the Vitest component.\n */\nexport interface VitestOptions {\n /**\n * Config file path.\n *\n * @default \"vitest.config.ts\"\n */\n readonly configFilePath?: string;\n\n /**\n * Vitest config (test block).\n */\n readonly config?: VitestConfigOptions;\n\n /**\n * Vitest version (overrides VERSION.VITEST_VERSION).\n */\n readonly vitestVersion?: string;\n}\n\n/**\n * Vitest component for Node/TypeScript projects.\n *\n * Adds Vitest as the test runner: devDeps, vitest.config.ts, and test/watch tasks.\n * Incompatible with Jest; use jest: false when constructing the project.\n */\nexport class Vitest extends Component {\n /**\n * Find the Vitest component on a project.\n */\n public static of(project: NodeProject): Vitest | undefined {\n const isVitest = (c: Component): c is Vitest => c instanceof Vitest;\n return project.components.find(isVitest);\n }\n\n private readonly configFilePath: string;\n private readonly include: string[];\n private readonly exclude: string[];\n private readonly environment: string;\n private readonly passWithNoTests: boolean;\n private readonly coverageEnabled: boolean;\n private readonly coverageDirectory: string;\n private readonly coverageReporters: string[];\n private readonly version: string;\n\n constructor(\n public readonly project: NodeProject,\n options: VitestOptions = {},\n ) {\n super(project);\n\n this.configFilePath = options.configFilePath ?? \"vitest.config.ts\";\n const config = options.config ?? {};\n this.include = config.include ?? [\"**/*.{test,spec}.?(c|m)[jt]s?(x)\"];\n this.exclude = config.exclude ?? [\n \"**/node_modules/**\",\n \"**/dist/**\",\n \"**/lib/**\",\n \"**/.?*\",\n ];\n this.environment = config.environment ?? \"node\";\n this.passWithNoTests = config.passWithNoTests ?? true;\n this.coverageEnabled = config.coverageEnabled ?? true;\n this.coverageDirectory = config.coverageDirectory ?? \"coverage\";\n this.coverageReporters = config.coverageReporters ?? [\"text\", \"lcov\"];\n this.version = options.vitestVersion ?? VERSION.VITEST_VERSION;\n\n project.addDevDeps(`vitest@${this.version}`);\n if (this.coverageEnabled) {\n project.addDevDeps(`@vitest/coverage-v8@${this.version}`);\n }\n\n const coveragePath = `/${this.coverageDirectory}/`;\n project.gitignore.addPatterns(coveragePath);\n project.npmignore?.exclude(coveragePath);\n\n this.addTestTasks();\n this.synthesizeConfig();\n }\n\n public override preSynthesize(): void {\n super.preSynthesize();\n for (const component of this.project.components) {\n if (component instanceof Jest) {\n throw new Error(\"Vitest cannot be used together with Jest\");\n }\n }\n }\n\n private addTestTasks(): void {\n // No receiveArgs so CI/turbo build:all always get a single run (no watch).\n // --update matches Jest's --updateSnapshot: updates snapshots when they mismatch.\n this.project.testTask.exec(\"vitest run --update\");\n\n if (!this.project.tasks.tryFind(\"test:watch\")) {\n this.project.addTask(\"test:watch\", {\n description: \"Run tests in watch mode\",\n exec: \"vitest watch\",\n receiveArgs: true,\n });\n }\n }\n\n private synthesizeConfig(): void {\n this.project.tryRemoveFile(this.configFilePath);\n new TextFile(this, this.configFilePath, {\n lines: this.renderConfig(),\n });\n }\n\n private renderConfig(): string[] {\n return [\n 'import { defineConfig } from \"vitest/config\";',\n \"\",\n \"export default defineConfig({\",\n \" test: {\",\n ` include: ${JSON.stringify(this.include)},`,\n ` exclude: ${JSON.stringify(this.exclude)},`,\n ` environment: \"${this.environment}\",`,\n ` passWithNoTests: ${this.passWithNoTests},`,\n \" coverage: {\",\n ` enabled: ${this.coverageEnabled},`,\n ` provider: \"v8\",`,\n ` reportsDirectory: \"${this.coverageDirectory}\",`,\n ` reporter: ${JSON.stringify(this.coverageReporters)},`,\n \" },\",\n \" },\",\n \"});\",\n ];\n }\n}\n","export const VERSION = {\n /**\n * Version of Astro to pin for AstroProject scaffolding.\n */\n ASTRO_VERSION: \"6.1.6\",\n\n /**\n * CDK CLI for workflows and command line operations.\n *\n * CLI and lib are versioned separately, so this is the CLI version.\n */\n AWS_CDK_CLI_VERSION: \"2.1118.0\",\n\n /**\n * CDK Version to use for construct projects.\n *\n * CLI and lib are versioned separately, so this is the lib version.\n */\n AWS_CDK_LIB_VERSION: \"2.250.0\",\n\n /**\n * Version of the AWS Constructs library to use.\n */\n AWS_CONSTRUCTS_VERSION: \"10.6.0\",\n\n /**\n * Version of Node.js to use in CI workflows at github actions.\n */\n NODE_WORKFLOWS: \"24\",\n\n /**\n * Version of `pnpm/action-setup` to use in GitHub workflows.\n * Tracks the version projen currently emits (see node_modules/projen/lib/javascript/node-project.js).\n */\n PNPM_ACTION_SETUP_VERSION: \"v5\",\n\n /**\n * Version of PNPM to use in workflows at github actions.\n */\n PNPM_VERSION: \"10.33.0\",\n\n /**\n * Version of Projen to use.\n */\n PROJEN_VERSION: \"0.99.48\",\n\n /**\n * Version of `actions/setup-node` to use in GitHub workflows.\n * Tracks the version projen currently emits (see node_modules/projen/lib/github/workflows.js).\n */\n SETUP_NODE_ACTION_VERSION: \"v6\",\n\n /**\n * Version of sharp to pin for StarlightProject (required peer for\n * Starlight's image optimization pipeline).\n */\n SHARP_VERSION: \"0.34.5\",\n\n /**\n * Version of @astrojs/starlight to pin for StarlightProject scaffolding.\n */\n STARLIGHT_VERSION: \"0.38.3\",\n\n /**\n * What version of the turborepo library should we use?\n */\n TURBO_VERSION: \"2.9.6\",\n\n /**\n * Version of @types/node to use across all packages (pnpm catalog).\n */\n TYPES_NODE_VERSION: \"25.6.0\",\n\n /**\n * What version of Vite to use (pnpm override). Pinned to 5.x so Vitest 4.x\n * can load config (Vite 6+/7+ are ESM-only; see issue #142). Remove override\n * when moving to ESM-only test setup.\n */\n VITE_VERSION: \"5.4.11\",\n\n /**\n * What version of Vitest to use when testRunner is 'vitest'.\n * Pinned to 3.x so it works with Vite 5 (Vitest 4 requires Vite 6). See issue #142.\n */\n VITEST_VERSION: \"3.2.4\",\n} as const;\n","import { Project } from \"projen/lib\";\nimport { Vitest } from \"../../vitest/vitest-component\";\nimport { AgentRuleBundle } from \"../agent-config-options\";\nimport { AGENT_RULE_SCOPE } from \"../types\";\nimport { findProjectsWithComponent, hasComponent } from \"./utils\";\n\n/**\n * Vitest bundle — auto-detected when the Vitest component is present.\n */\nexport const vitestBundle: AgentRuleBundle = {\n name: \"vitest\",\n description: \"Vitest testing conventions, patterns, and file scoping\",\n appliesWhen: (project: Project) => hasComponent(project, Vitest),\n findApplicableProjects: (project: Project) =>\n findProjectsWithComponent(project, Vitest),\n rules: [\n {\n name: \"vitest-testing\",\n description: \"Vitest testing conventions and patterns\",\n scope: AGENT_RULE_SCOPE.FILE_PATTERN,\n filePatterns: [\"**/*.test.ts\", \"**/*.spec.ts\"],\n content: [\n \"# Vitest Testing Patterns\",\n \"\",\n \"## Mandatory Requirements\",\n \"\",\n \"- **Tests MUST be created or updated whenever code functionality is added or changed**\",\n \"- This applies to all code changes, including:\",\n \" - New features and functionality\",\n \" - Bug fixes\",\n \" - Refactoring that changes behavior\",\n \" - API changes\",\n \" - Configuration changes that affect functionality\",\n \"- Tests should be written or updated as part of the same change that modifies the code\",\n \"\",\n \"## Test Structure\",\n \"\",\n \"- Use **Vitest** as the test runner\",\n \"- Test files: `.spec.ts` or `.test.ts` (co-located with source)\",\n \"- Use descriptive test names: `describe('ClassName', () => { it('should do something specific', () => {}) })`\",\n \"- Prefer snapshot tests for complex object structures\",\n \"- Mock external dependencies appropriately\",\n \"\",\n \"## Test Organization\",\n \"\",\n \"- Co-locate test files with source files\",\n \"- Test files can use dev dependencies (ESLint rule override)\",\n \"- Import from `vitest`: `import { describe, expect, it } from 'vitest'`\",\n \"\",\n \"## Example Test Structure\",\n \"\",\n \"```typescript\",\n \"import { describe, expect, it } from 'vitest';\",\n \"import { MyClass } from './my-class';\",\n \"\",\n \"describe('MyClass', () => {\",\n \" it('should do something specific', () => {\",\n \" // Test implementation\",\n \" });\",\n \"});\",\n \"```\",\n ].join(\"\\n\"),\n tags: [\"testing\"],\n },\n ],\n claudePermissions: {\n allow: [\"Bash(npx vitest:*)\"],\n },\n};\n","import { AgentRuleBundle } from \"../agent-config-options\";\nimport { awsCdkBundle } from \"./aws-cdk\";\nimport { baseBundle } from \"./base\";\nimport { bcmWriterBundle } from \"./bcm-writer\";\nimport { companyProfileBundle } from \"./company-profile\";\nimport { githubWorkflowBundle } from \"./github-workflow\";\nimport { industryDiscoveryBundle } from \"./industry-discovery\";\nimport { jestBundle } from \"./jest\";\nimport { maintenanceAuditBundle } from \"./maintenance-audit\";\nimport { meetingAnalysisBundle } from \"./meeting-analysis\";\nimport { orchestratorBundle } from \"./orchestrator\";\nimport { peopleProfileBundle } from \"./people-profile\";\nimport { pnpmBundle } from \"./pnpm\";\nimport { prReviewBundle } from \"./pr-review\";\nimport { projenBundle } from \"./projen\";\nimport { requirementsAnalystBundle } from \"./requirements-analyst\";\nimport { researchPipelineBundle } from \"./research-pipeline\";\nimport { slackBundle } from \"./slack\";\nimport { softwareProfileBundle } from \"./software-profile\";\nimport { turborepoBundle } from \"./turborepo\";\nimport { typescriptBundle } from \"./typescript\";\nimport { vitestBundle } from \"./vitest\";\n\nexport { awsCdkBundle } from \"./aws-cdk\";\nexport { baseBundle } from \"./base\";\nexport { bcmWriterBundle } from \"./bcm-writer\";\nexport { companyProfileBundle } from \"./company-profile\";\nexport { githubWorkflowBundle } from \"./github-workflow\";\nexport { industryDiscoveryBundle } from \"./industry-discovery\";\nexport { jestBundle } from \"./jest\";\nexport { maintenanceAuditBundle } from \"./maintenance-audit\";\nexport { meetingAnalysisBundle } from \"./meeting-analysis\";\nexport { orchestratorBundle } from \"./orchestrator\";\nexport { peopleProfileBundle } from \"./people-profile\";\nexport { pnpmBundle } from \"./pnpm\";\nexport { prReviewBundle } from \"./pr-review\";\nexport { projenBundle } from \"./projen\";\nexport { requirementsAnalystBundle } from \"./requirements-analyst\";\nexport { researchPipelineBundle } from \"./research-pipeline\";\nexport { slackBundle } from \"./slack\";\nexport { softwareProfileBundle } from \"./software-profile\";\nexport { turborepoBundle } from \"./turborepo\";\nexport { typescriptBundle } from \"./typescript\";\nexport { vitestBundle } from \"./vitest\";\n\n/**\n * Built-in rule bundles that ship with configulator.\n * Each bundle is auto-detected based on project introspection.\n *\n * Order matters: base is first so its rules can be overridden by\n * more specific bundles. The base bundle's `appliesWhen` always\n * returns true; it is filtered by the `includeBaseRules` option\n * in AgentConfig.\n */\nexport const BUILT_IN_BUNDLES: ReadonlyArray<AgentRuleBundle> = [\n baseBundle,\n typescriptBundle,\n vitestBundle,\n jestBundle,\n turborepoBundle,\n pnpmBundle,\n awsCdkBundle,\n projenBundle,\n githubWorkflowBundle,\n slackBundle,\n meetingAnalysisBundle,\n orchestratorBundle,\n prReviewBundle,\n requirementsAnalystBundle,\n researchPipelineBundle,\n companyProfileBundle,\n peopleProfileBundle,\n softwareProfileBundle,\n industryDiscoveryBundle,\n bcmWriterBundle,\n maintenanceAuditBundle,\n];\n","import * as path from \"node:path\";\nimport { Project } from \"projen/lib\";\n\n/**\n * Minimal shape projen's `TypescriptConfig` exposes for reading back the\n * final `include` array. We duck-type against it because non-TypeScript\n * projects don't have `tsconfig` at all.\n */\ninterface TypescriptConfigLike {\n readonly include: ReadonlyArray<string>;\n}\n\ninterface WithTsconfig {\n readonly tsconfig?: TypescriptConfigLike;\n}\n\ninterface WithSrcdir {\n readonly srcdir?: string;\n}\n\n/**\n * For each detected project, read its `tsconfig.include` and prefix each\n * entry with the project's outdir relative to the root. Returns a\n * deduplicated, sorted array of scoped glob patterns suitable for use as a\n * rule's `filePatterns`.\n *\n * Projects without a `tsconfig` fall back to `<relOutdir>/<srcdir>/**\\/*.ts`\n * (srcdir defaults to `\"src\"`), which matches projen's defaults for any\n * plain `TypeScriptProject`.\n */\nexport function scopeFilePatternsToProjects(\n root: Project,\n detected: ReadonlyArray<Project>,\n): Array<string> {\n const patterns = new Set<string>();\n\n for (const project of detected) {\n const rel = path.relative(root.outdir, project.outdir);\n const include = readTsconfigInclude(project);\n\n if (include && include.length > 0) {\n for (const entry of include) {\n patterns.add(prefix(rel, entry));\n }\n } else {\n const srcdir = (project as WithSrcdir).srcdir ?? \"src\";\n patterns.add(prefix(rel, path.posix.join(srcdir, \"**/*.ts\")));\n }\n }\n\n return [...patterns].sort();\n}\n\n/**\n * Read the `tsconfig.include` array from a projen Project, if present.\n * Returns `undefined` for projects without a tsconfig component.\n */\nfunction readTsconfigInclude(\n project: Project,\n): ReadonlyArray<string> | undefined {\n const tsconfig = (project as WithTsconfig).tsconfig;\n if (!tsconfig) {\n return undefined;\n }\n return tsconfig.include;\n}\n\n/**\n * Join a project-relative prefix with a glob entry using POSIX separators so\n * rendered rule files are stable across platforms. An empty `rel` means the\n * detected project is the root itself — return the entry unchanged.\n */\nfunction prefix(rel: string, entry: string): string {\n if (!rel) {\n return entry;\n }\n return path.posix.join(rel, entry);\n}\n","import { Component, JsonFile } from \"projen\";\nimport { TextFile } from \"projen/lib/textfile\";\nimport { ClaudeSettingsConfig } from \"../agent-config-options\";\nimport {\n AGENT_RULE_SCOPE,\n AgentProcedure,\n AgentRule,\n AgentSkill,\n AgentSubAgent,\n CLAUDE_RULE_TARGET,\n McpServerConfig,\n resolveModelAlias,\n} from \"../types\";\n\nconst GENERATED_MARKER =\n \"<!-- ~~ Generated by @codedrifters/configulator. Edits welcome — please contribute improvements back. ~~ -->\";\n\n/**\n * Renders agent configuration files for Claude Code.\n *\n * Output files:\n * - CLAUDE.md — always-active rules targeted to CLAUDE_MD\n * - .claude/rules/{name}.md — scoped rules with optional paths frontmatter\n * - .claude/settings.json — permissions, hooks, MCP servers, sandbox\n * - .claude/skills/{name}/SKILL.md — skill definitions\n * - .claude/agents/{name}.md — sub-agent definitions\n * - .claude/procedures/{name} — executable procedures (shell scripts)\n */\nexport class ClaudeRenderer {\n /**\n * Render all Claude Code configuration files.\n */\n public static render(\n component: Component,\n rules: ReadonlyArray<AgentRule>,\n skills: ReadonlyArray<AgentSkill>,\n subAgents: ReadonlyArray<AgentSubAgent>,\n mcpServers: Readonly<Record<string, McpServerConfig>>,\n settings?: ClaudeSettingsConfig,\n procedures?: ReadonlyArray<AgentProcedure>,\n ): void {\n ClaudeRenderer.renderClaudeMd(component, rules);\n ClaudeRenderer.renderScopedRules(component, rules);\n ClaudeRenderer.renderSettings(component, mcpServers, settings);\n ClaudeRenderer.renderSkills(component, skills);\n ClaudeRenderer.renderSubAgents(component, subAgents);\n if (procedures && procedures.length > 0) {\n ClaudeRenderer.renderProcedures(component, procedures);\n }\n }\n\n private static renderClaudeMd(\n component: Component,\n rules: ReadonlyArray<AgentRule>,\n ): void {\n const claudeMdRules = rules.filter((r) => {\n if (r.platforms?.claude?.exclude) return false;\n const target =\n r.platforms?.claude?.target ?? ClaudeRenderer.defaultTarget(r);\n return target === CLAUDE_RULE_TARGET.CLAUDE_MD;\n });\n\n if (claudeMdRules.length === 0) return;\n\n const lines: string[] = [GENERATED_MARKER, \"\"];\n for (let i = 0; i < claudeMdRules.length; i++) {\n if (i > 0) lines.push(\"\", \"---\", \"\");\n lines.push(...claudeMdRules[i].content.split(\"\\n\"));\n }\n\n new TextFile(component, \"CLAUDE.md\", { lines });\n }\n\n private static renderScopedRules(\n component: Component,\n rules: ReadonlyArray<AgentRule>,\n ): void {\n const scopedRules = rules.filter((r) => {\n if (r.platforms?.claude?.exclude) return false;\n const target =\n r.platforms?.claude?.target ?? ClaudeRenderer.defaultTarget(r);\n return target === CLAUDE_RULE_TARGET.SCOPED_FILE;\n });\n\n for (const rule of scopedRules) {\n const lines: string[] = [];\n\n if (rule.filePatterns && rule.filePatterns.length > 0) {\n lines.push(\"---\");\n lines.push(\"paths:\");\n for (const pattern of rule.filePatterns) {\n lines.push(` - \"${pattern}\"`);\n }\n lines.push(\"---\");\n lines.push(\"\");\n }\n\n lines.push(...rule.content.split(\"\\n\"));\n\n new TextFile(component, `.claude/rules/${rule.name}.md`, { lines });\n }\n }\n\n private static renderSettings(\n component: Component,\n mcpServers: Readonly<Record<string, McpServerConfig>>,\n settings?: ClaudeSettingsConfig,\n ): void {\n const obj: Record<string, unknown> = {};\n let hasContent = false;\n\n if (settings?.defaultMode) {\n obj.defaultMode = settings.defaultMode;\n hasContent = true;\n }\n\n if (settings?.permissions) {\n const perms: Record<string, unknown> = {};\n if (settings.permissions.allow?.length) {\n perms.allow = [...settings.permissions.allow];\n }\n if (settings.permissions.deny?.length) {\n perms.deny = [...settings.permissions.deny];\n }\n if (settings.permissions.ask?.length) {\n perms.ask = [...settings.permissions.ask];\n }\n if (settings.permissions.additionalDirectories?.length) {\n perms.additionalDirectories = [\n ...settings.permissions.additionalDirectories,\n ];\n }\n if (Object.keys(perms).length > 0) {\n obj.permissions = perms;\n hasContent = true;\n }\n }\n\n if (settings?.hooks) {\n const hooks: Record<string, unknown> = {};\n for (const [event, entries] of Object.entries(settings.hooks)) {\n if (entries && entries.length > 0) {\n hooks[event] = entries;\n }\n }\n if (Object.keys(hooks).length > 0) {\n obj.hooks = hooks;\n hasContent = true;\n }\n }\n\n // MCP servers from both cross-platform and Claude-specific config\n const allMcpServers: Record<string, unknown> = {};\n\n // Cross-platform MCP servers\n for (const [name, config] of Object.entries(mcpServers)) {\n allMcpServers[name] = ClaudeRenderer.buildMcpServerObj(config);\n }\n\n // Claude-specific MCP servers\n if (settings?.mcpServers) {\n for (const [name, config] of Object.entries(settings.mcpServers)) {\n allMcpServers[name] = ClaudeRenderer.buildMcpServerObj(config);\n }\n }\n\n if (Object.keys(allMcpServers).length > 0) {\n obj.mcpServers = allMcpServers;\n hasContent = true;\n }\n\n if (settings?.allowedMcpServers?.length) {\n obj.allowedMcpServers = [...settings.allowedMcpServers];\n hasContent = true;\n }\n\n if (settings?.deniedMcpServers?.length) {\n obj.deniedMcpServers = [...settings.deniedMcpServers];\n hasContent = true;\n }\n\n if (settings?.env && Object.keys(settings.env).length > 0) {\n obj.env = { ...settings.env };\n hasContent = true;\n }\n\n if (settings?.sandbox) {\n obj.sandbox = ClaudeRenderer.buildSandboxObj(settings.sandbox);\n hasContent = true;\n }\n\n if (settings?.autoMode) {\n const autoMode: Record<string, unknown> = {};\n if (settings.autoMode.environment?.length) {\n autoMode.environment = [...settings.autoMode.environment];\n }\n if (settings.autoMode.allow?.length) {\n autoMode.allow = [...settings.autoMode.allow];\n }\n if (settings.autoMode.soft_deny?.length) {\n autoMode.soft_deny = [...settings.autoMode.soft_deny];\n }\n if (Object.keys(autoMode).length > 0) {\n obj.autoMode = autoMode;\n hasContent = true;\n }\n }\n\n if (settings?.disableBypassPermissionsMode) {\n obj.disableBypassPermissionsMode = settings.disableBypassPermissionsMode;\n hasContent = true;\n }\n\n if (settings?.disableAutoMode) {\n obj.disableAutoMode = settings.disableAutoMode;\n hasContent = true;\n }\n\n if (settings?.disableAllHooks !== undefined) {\n obj.disableAllHooks = settings.disableAllHooks;\n hasContent = true;\n }\n\n if (settings?.excludeSensitivePatterns?.length) {\n obj.excludeSensitivePatterns = [...settings.excludeSensitivePatterns];\n hasContent = true;\n }\n\n if (settings?.model) {\n obj.model = settings.model;\n hasContent = true;\n }\n\n if (settings?.effortLevel) {\n obj.effortLevel = settings.effortLevel;\n hasContent = true;\n }\n\n if (settings?.attribution) {\n obj.attribution = settings.attribution;\n hasContent = true;\n }\n\n if (settings?.claudeMdExcludes?.length) {\n obj.claudeMdExcludes = [...settings.claudeMdExcludes];\n hasContent = true;\n }\n\n if (settings?.respectGitignore !== undefined) {\n obj.respectGitignore = settings.respectGitignore;\n hasContent = true;\n }\n\n if (!hasContent) return;\n\n new JsonFile(component, \".claude/settings.json\", { obj });\n }\n\n private static buildSandboxObj(\n sandbox: NonNullable<ClaudeSettingsConfig[\"sandbox\"]>,\n ): Record<string, unknown> {\n const obj: Record<string, unknown> = {};\n if (sandbox.enabled !== undefined) obj.enabled = sandbox.enabled;\n if (sandbox.mode) obj.mode = sandbox.mode;\n if (sandbox.failIfUnavailable !== undefined) {\n obj.failIfUnavailable = sandbox.failIfUnavailable;\n }\n if (sandbox.autoAllowBashIfSandboxed !== undefined) {\n obj.autoAllowBashIfSandboxed = sandbox.autoAllowBashIfSandboxed;\n }\n if (sandbox.excludedCommands?.length) {\n obj.excludedCommands = [...sandbox.excludedCommands];\n }\n if (sandbox.filesystem) {\n const fs: Record<string, unknown> = {};\n if (sandbox.filesystem.allowRead?.length) {\n fs.allowRead = [...sandbox.filesystem.allowRead];\n }\n if (sandbox.filesystem.denyRead?.length) {\n fs.denyRead = [...sandbox.filesystem.denyRead];\n }\n if (sandbox.filesystem.allowWrite?.length) {\n fs.allowWrite = [...sandbox.filesystem.allowWrite];\n }\n if (sandbox.filesystem.denyWrite?.length) {\n fs.denyWrite = [...sandbox.filesystem.denyWrite];\n }\n if (Object.keys(fs).length > 0) obj.filesystem = fs;\n }\n if (sandbox.network) {\n const net: Record<string, unknown> = {};\n if (sandbox.network.allowedDomains?.length) {\n net.allowedDomains = [...sandbox.network.allowedDomains];\n }\n if (sandbox.network.denyDomains?.length) {\n net.denyDomains = [...sandbox.network.denyDomains];\n }\n if (Object.keys(net).length > 0) obj.network = net;\n }\n return obj;\n }\n\n private static renderSkills(\n component: Component,\n skills: ReadonlyArray<AgentSkill>,\n ): void {\n for (const skill of skills) {\n if (skill.platforms?.claude?.exclude) continue;\n\n const lines: string[] = [];\n lines.push(\"---\");\n lines.push(`name: \"${skill.name}\"`);\n lines.push(`description: \"${skill.description}\"`);\n if (skill.disableModelInvocation) {\n lines.push(`disable-model-invocation: true`);\n }\n if (skill.userInvocable === false) {\n lines.push(`user-invocable: false`);\n }\n const resolvedSkillModel = resolveModelAlias(skill.model);\n if (resolvedSkillModel) {\n lines.push(`model: \"${resolvedSkillModel}\"`);\n }\n if (skill.effort) {\n lines.push(`effort: \"${skill.effort}\"`);\n }\n if (skill.paths && skill.paths.length > 0) {\n lines.push(`paths:`);\n for (const p of skill.paths) {\n lines.push(` - \"${p}\"`);\n }\n }\n if (skill.context) {\n lines.push(`context: \"${skill.context}\"`);\n }\n if (skill.agent) {\n lines.push(`agent: \"${skill.agent}\"`);\n }\n if (skill.shell) {\n lines.push(`shell: \"${skill.shell}\"`);\n }\n if (skill.allowedTools && skill.allowedTools.length > 0) {\n lines.push(`allowed-tools:`);\n for (const tool of skill.allowedTools) {\n lines.push(` - \"${tool}\"`);\n }\n }\n lines.push(\"---\");\n lines.push(\"\");\n lines.push(...skill.instructions.split(\"\\n\"));\n\n new TextFile(component, `.claude/skills/${skill.name}/SKILL.md`, {\n lines,\n });\n\n if (skill.referenceFiles && skill.referenceFiles.length > 0) {\n for (const file of skill.referenceFiles) {\n new TextFile(component, `.claude/skills/${skill.name}/${file.path}`, {\n lines: file.content.split(\"\\n\"),\n });\n }\n }\n }\n }\n\n private static renderSubAgents(\n component: Component,\n subAgents: ReadonlyArray<AgentSubAgent>,\n ): void {\n for (const agent of subAgents) {\n if (agent.platforms?.claude?.exclude) continue;\n\n const lines: string[] = [];\n lines.push(\"---\");\n lines.push(`name: ${agent.name}`);\n lines.push(`description: >-`);\n lines.push(` ${agent.description}`);\n const resolvedModel = resolveModelAlias(agent.model);\n if (resolvedModel) {\n lines.push(`model: ${resolvedModel}`);\n }\n if (agent.tools && agent.tools.length > 0) {\n lines.push(`tools:`);\n for (const tool of agent.tools) {\n lines.push(` - \"${tool}\"`);\n }\n }\n if (agent.disallowedTools && agent.disallowedTools.length > 0) {\n lines.push(`disallowedTools:`);\n for (const tool of agent.disallowedTools) {\n lines.push(` - \"${tool}\"`);\n }\n }\n if (agent.maxTurns) {\n lines.push(`maxTurns: ${agent.maxTurns}`);\n }\n if (agent.skills && agent.skills.length > 0) {\n lines.push(`skills:`);\n for (const skill of agent.skills) {\n lines.push(` - \"${skill}\"`);\n }\n }\n if (agent.platforms?.claude?.permissionMode) {\n lines.push(`permissionMode: ${agent.platforms.claude.permissionMode}`);\n }\n if (agent.platforms?.claude?.isolation) {\n lines.push(`isolation: ${agent.platforms.claude.isolation}`);\n }\n if (agent.platforms?.claude?.background) {\n lines.push(`background: true`);\n }\n if (agent.platforms?.claude?.effort) {\n lines.push(`effort: ${agent.platforms.claude.effort}`);\n }\n if (agent.platforms?.claude?.memory) {\n lines.push(`memory: ${agent.platforms.claude.memory}`);\n }\n if (agent.canDelegateToAgents && agent.canDelegateToAgents.length > 0) {\n lines.push(`canDelegateToAgents:`);\n for (const delegateName of agent.canDelegateToAgents) {\n lines.push(` - \"${delegateName}\"`);\n }\n }\n lines.push(\"---\");\n lines.push(\"\");\n lines.push(...agent.prompt.split(\"\\n\"));\n\n new TextFile(component, `.claude/agents/${agent.name}.md`, { lines });\n }\n }\n\n private static buildMcpServerObj(\n config: McpServerConfig,\n ): Record<string, unknown> {\n const server: Record<string, unknown> = {};\n if (config.transport) server.type = config.transport;\n if (config.command) server.command = config.command;\n if (config.args) server.args = [...config.args];\n if (config.url) server.url = config.url;\n if (config.headers && Object.keys(config.headers).length > 0) {\n server.headers = { ...config.headers };\n }\n if (config.env) server.env = { ...config.env };\n return server;\n }\n\n private static renderProcedures(\n component: Component,\n procedures: ReadonlyArray<AgentProcedure>,\n ): void {\n for (const proc of procedures) {\n new TextFile(component, `.claude/procedures/${proc.name}`, {\n lines: proc.content.split(\"\\n\"),\n executable: true,\n });\n }\n }\n\n /**\n * Determine the default Claude rule target based on rule scope.\n * ALWAYS-scoped rules default to CLAUDE_MD; FILE_PATTERN rules default to SCOPED_FILE.\n */\n private static defaultTarget(rule: AgentRule): string {\n return rule.scope === AGENT_RULE_SCOPE.ALWAYS\n ? CLAUDE_RULE_TARGET.CLAUDE_MD\n : CLAUDE_RULE_TARGET.SCOPED_FILE;\n }\n}\n","import { Component } from \"projen\";\nimport { AgentRule, AgentSkill, AgentSubAgent } from \"../types\";\n\n/**\n * Renders agent configuration files for OpenAI Codex.\n *\n * Output files (future):\n * - AGENTS.md — root-level instructions\n * - {dir}/AGENTS.md — directory-scoped instructions\n *\n * TODO: Implement in a future issue.\n */\nexport class CodexRenderer {\n public static render(\n _component: Component,\n _rules: ReadonlyArray<AgentRule>,\n _skills: ReadonlyArray<AgentSkill>,\n _subAgents: ReadonlyArray<AgentSubAgent>,\n ): void {\n // Codex renderer is not yet implemented.\n }\n}\n","import { Component } from \"projen\";\nimport { AgentRule, AgentSkill, AgentSubAgent } from \"../types\";\n\n/**\n * Renders agent configuration files for GitHub Copilot.\n *\n * Output files (future):\n * - .github/copilot-instructions.md — root instructions\n * - .github/instructions/*.instructions.md — scoped instructions\n *\n * TODO: Implement in a future issue.\n */\nexport class CopilotRenderer {\n public static render(\n _component: Component,\n _rules: ReadonlyArray<AgentRule>,\n _skills: ReadonlyArray<AgentSkill>,\n _subAgents: ReadonlyArray<AgentSubAgent>,\n ): void {\n // Copilot renderer is not yet implemented.\n }\n}\n","import { Component, JsonFile } from \"projen\";\nimport { TextFile } from \"projen/lib/textfile\";\nimport { CursorSettingsConfig } from \"../agent-config-options\";\nimport {\n AGENT_RULE_SCOPE,\n AgentRule,\n AgentSkill,\n AgentSubAgent,\n McpServerConfig,\n} from \"../types\";\n\nconst GENERATED_MARKER =\n \"# ~~ Generated by @codedrifters/configulator. Edits welcome — please contribute improvements back. ~~\";\n\n/**\n * Renders agent configuration files for Cursor.\n *\n * Output files:\n * - .cursor/rules/{name}.mdc — YAML frontmatter + markdown body\n * - .cursor/agents/{name}.md — sub-agent definitions\n * - .cursor/mcp.json — MCP server configuration\n * - .cursor/hooks.json — lifecycle hooks\n * - .cursorignore — hard security boundary\n * - .cursorindexingignore — soft indexing boundary\n */\nexport class CursorRenderer {\n /**\n * Render all Cursor configuration files.\n */\n public static render(\n component: Component,\n rules: ReadonlyArray<AgentRule>,\n skills: ReadonlyArray<AgentSkill>,\n subAgents: ReadonlyArray<AgentSubAgent>,\n mcpServers: Readonly<Record<string, McpServerConfig>>,\n settings?: CursorSettingsConfig,\n ): void {\n CursorRenderer.renderRules(component, rules);\n CursorRenderer.renderSkills(component, skills);\n CursorRenderer.renderSubAgents(component, subAgents);\n CursorRenderer.renderMcpServers(component, mcpServers);\n CursorRenderer.renderHooks(component, settings);\n CursorRenderer.renderIgnoreFiles(component, settings);\n }\n\n private static renderRules(\n component: Component,\n rules: ReadonlyArray<AgentRule>,\n ): void {\n for (const rule of rules) {\n if (rule.platforms?.cursor?.exclude) continue;\n\n const lines: string[] = [];\n const description =\n rule.platforms?.cursor?.description ?? rule.description;\n const isAlways = rule.scope === AGENT_RULE_SCOPE.ALWAYS;\n\n // YAML frontmatter\n lines.push(\"---\");\n lines.push(`description: \"${description}\"`);\n lines.push(`alwaysApply: ${isAlways}`);\n if (!isAlways && rule.filePatterns && rule.filePatterns.length > 0) {\n lines.push(`path: ${JSON.stringify([...rule.filePatterns])}`);\n }\n lines.push(\"---\");\n lines.push(\"\");\n lines.push(...rule.content.split(\"\\n\"));\n\n new TextFile(component, `.cursor/rules/${rule.name}.mdc`, { lines });\n }\n }\n\n private static renderSkills(\n component: Component,\n skills: ReadonlyArray<AgentSkill>,\n ): void {\n for (const skill of skills) {\n if (skill.platforms?.cursor?.exclude) continue;\n\n const lines: string[] = [];\n lines.push(\"---\");\n lines.push(`name: \"${skill.name}\"`);\n lines.push(`description: \"${skill.description}\"`);\n if (skill.disableModelInvocation) {\n lines.push(`disable-model-invocation: true`);\n }\n if (skill.userInvocable === false) {\n lines.push(`user-invocable: false`);\n }\n if (skill.context) {\n lines.push(`context: \"${skill.context}\"`);\n }\n if (skill.agent) {\n lines.push(`agent: \"${skill.agent}\"`);\n }\n if (skill.shell) {\n lines.push(`shell: \"${skill.shell}\"`);\n }\n if (skill.allowedTools && skill.allowedTools.length > 0) {\n lines.push(`allowed-tools:`);\n for (const tool of skill.allowedTools) {\n lines.push(` - \"${tool}\"`);\n }\n }\n lines.push(\"---\");\n lines.push(\"\");\n lines.push(...skill.instructions.split(\"\\n\"));\n\n new TextFile(component, `.cursor/skills/${skill.name}/SKILL.md`, {\n lines,\n });\n\n if (skill.referenceFiles && skill.referenceFiles.length > 0) {\n for (const file of skill.referenceFiles) {\n new TextFile(component, `.cursor/skills/${skill.name}/${file.path}`, {\n lines: file.content.split(\"\\n\"),\n });\n }\n }\n }\n }\n\n private static renderSubAgents(\n component: Component,\n subAgents: ReadonlyArray<AgentSubAgent>,\n ): void {\n for (const agent of subAgents) {\n if (agent.platforms?.cursor?.exclude) continue;\n\n const lines: string[] = [];\n lines.push(\"---\");\n lines.push(`name: ${agent.name}`);\n lines.push(`description: >-`);\n lines.push(` ${agent.description}`);\n // Cursor uses its own model selection; omit the model field\n // to let it use its default (e.g., composer).\n if (agent.platforms?.cursor?.readonly) {\n lines.push(`readonly: true`);\n }\n if (agent.platforms?.cursor?.isBackground) {\n lines.push(`is_background: true`);\n }\n lines.push(\"---\");\n lines.push(\"\");\n lines.push(...agent.prompt.split(\"\\n\"));\n\n new TextFile(component, `.cursor/agents/${agent.name}.md`, { lines });\n }\n }\n\n private static renderMcpServers(\n component: Component,\n mcpServers: Readonly<Record<string, McpServerConfig>>,\n ): void {\n const serverNames = Object.keys(mcpServers);\n if (serverNames.length === 0) return;\n\n const obj: Record<string, unknown> = { mcpServers: {} };\n const servers = obj.mcpServers as Record<string, unknown>;\n\n for (const [name, config] of Object.entries(mcpServers)) {\n const server: Record<string, unknown> = {};\n if (config.transport) server.transport = config.transport;\n if (config.command) server.command = config.command;\n if (config.args) server.args = [...config.args];\n if (config.url) server.url = config.url;\n if (config.headers && Object.keys(config.headers).length > 0) {\n server.headers = { ...config.headers };\n }\n if (config.env) server.env = { ...config.env };\n servers[name] = server;\n }\n\n new JsonFile(component, \".cursor/mcp.json\", { obj });\n }\n\n private static renderHooks(\n component: Component,\n settings?: CursorSettingsConfig,\n ): void {\n if (!settings?.hooks) return;\n\n const hooks: Record<string, unknown[]> = {};\n const hookEntries = settings.hooks;\n\n // Render all hook events dynamically\n for (const [event, actions] of Object.entries(hookEntries)) {\n if (actions && actions.length > 0) {\n hooks[event] = actions.map((h: { command: string }) => ({\n command: h.command,\n }));\n }\n }\n\n if (Object.keys(hooks).length === 0) return;\n\n new JsonFile(component, \".cursor/hooks.json\", {\n obj: { version: 1, hooks },\n });\n }\n\n private static renderIgnoreFiles(\n component: Component,\n settings?: CursorSettingsConfig,\n ): void {\n if (settings?.ignorePatterns && settings.ignorePatterns.length > 0) {\n new TextFile(component, \".cursorignore\", {\n lines: [GENERATED_MARKER, \"\", ...settings.ignorePatterns],\n });\n }\n\n if (\n settings?.indexingIgnorePatterns &&\n settings.indexingIgnorePatterns.length > 0\n ) {\n new TextFile(component, \".cursorindexingignore\", {\n lines: [GENERATED_MARKER, \"\", ...settings.indexingIgnorePatterns],\n });\n }\n }\n}\n","import { ResolvedProjectMetadata } from \"../projects/project-metadata-options\";\n\n/**\n * Default fallback placeholders for unresolved template variables.\n */\nconst FALLBACKS: Record<string, string> = {\n \"repository.owner\": \"<owner>\",\n \"repository.name\": \"<repo>\",\n \"repository.defaultBranch\": \"main\",\n \"organization.name\": \"<organization>\",\n \"organization.githubOrg\": \"<org>\",\n \"githubProject.name\": \"<project-name>\",\n \"githubProject.number\": \"<project-number>\",\n \"githubProject.nodeId\": \"<project-node-id>\",\n docsPath: \"<docs-path>\",\n};\n\n/** Matches `{{dotted.path}}` template variables. */\nconst TEMPLATE_RE = /\\{\\{(\\w+(?:\\.\\w+)*)\\}\\}/g;\n\n/**\n * Looks up a dotted path (e.g., \"repository.owner\") on a metadata object.\n * Returns the value as a string, or undefined if not found.\n */\nfunction getNestedValue(\n obj: Record<string, unknown>,\n path: string,\n): string | undefined {\n const parts = path.split(\".\");\n let current: unknown = obj;\n\n for (const part of parts) {\n if (current == null || typeof current !== \"object\") {\n return undefined;\n }\n current = (current as Record<string, unknown>)[part];\n }\n\n if (current == null) {\n return undefined;\n }\n\n return String(current);\n}\n\n/**\n * Result of template variable resolution.\n */\nexport interface TemplateResolveResult {\n /** The template string with all variables resolved or replaced with fallbacks. */\n readonly resolved: string;\n /** Template variable keys that could not be resolved from metadata. */\n readonly unresolvedKeys: ReadonlyArray<string>;\n}\n\n/**\n * Resolves `{{dotted.path}}` template variables in a string using project metadata.\n * Unresolved variables are replaced with their fallback placeholders.\n *\n * @param template - String potentially containing `{{variable}}` patterns\n * @param metadata - Resolved project metadata, or undefined if not available\n * @returns The resolved string and a list of any unresolved variable keys\n */\nexport function resolveTemplateVariables(\n template: string,\n metadata: ResolvedProjectMetadata | undefined,\n): TemplateResolveResult {\n if (!TEMPLATE_RE.test(template)) {\n return { resolved: template, unresolvedKeys: [] };\n }\n\n const unresolvedKeys: string[] = [];\n\n // Reset regex lastIndex since we used .test() above\n TEMPLATE_RE.lastIndex = 0;\n\n const resolved = template.replace(TEMPLATE_RE, (_match, key: string) => {\n if (metadata) {\n const value = getNestedValue(\n metadata as unknown as Record<string, unknown>,\n key,\n );\n if (value !== undefined) {\n return value;\n }\n }\n\n unresolvedKeys.push(key);\n return FALLBACKS[key] ?? `<${key}>`;\n });\n\n return { resolved, unresolvedKeys };\n}\n","import { Component } from \"projen\";\nimport { NodeProject } from \"projen/lib/javascript\";\nimport { TextFile } from \"projen/lib/textfile\";\nimport {\n AstroConfigOptions,\n AstroIntegrationSpec,\n} from \"./astro-config-options\";\n\n/**\n * Renders `astro.config.mjs` for an Astro project.\n */\nexport class AstroConfig extends Component {\n /**\n * Find the AstroConfig component on a project.\n */\n public static of(project: NodeProject): AstroConfig | undefined {\n const isAstroConfig = (c: Component): c is AstroConfig =>\n c instanceof AstroConfig;\n return project.components.find(isAstroConfig);\n }\n\n private readonly configFilePath: string;\n private readonly site?: string;\n private readonly base?: string;\n private readonly output?: string;\n private readonly integrations: Array<AstroIntegrationSpec>;\n private readonly adapter?: AstroIntegrationSpec;\n\n constructor(\n public readonly project: NodeProject,\n options: AstroConfigOptions = {},\n ) {\n super(project);\n\n this.configFilePath = \"astro.config.mjs\";\n this.site = options.site;\n this.base = options.base;\n this.output = options.output;\n this.integrations = options.integrations ?? [];\n this.adapter = options.adapter;\n\n this.synthesizeConfig();\n }\n\n /**\n * Render the config file contents as an array of lines.\n *\n * Exposed for unit testing — `synthesizeConfig` writes these to disk.\n */\n public renderConfig(): Array<string> {\n const imports: Array<string> = [\n 'import { defineConfig } from \"astro/config\";',\n ];\n const specs: Array<AstroIntegrationSpec> = [\n ...this.integrations,\n ...(this.adapter ? [this.adapter] : []),\n ];\n for (const spec of specs) {\n imports.push(renderImport(spec));\n }\n\n const body: Array<string> = [];\n if (this.site !== undefined) {\n body.push(` site: ${JSON.stringify(this.site)},`);\n }\n if (this.base !== undefined) {\n body.push(` base: ${JSON.stringify(this.base)},`);\n }\n if (this.output !== undefined) {\n body.push(` output: ${JSON.stringify(this.output)},`);\n }\n if (this.integrations.length > 0) {\n const calls = this.integrations.map(renderCall).join(\", \");\n body.push(` integrations: [${calls}],`);\n }\n if (this.adapter) {\n body.push(` adapter: ${renderCall(this.adapter)},`);\n }\n\n return [...imports, \"\", \"export default defineConfig({\", ...body, \"});\"];\n }\n\n private synthesizeConfig(): void {\n this.project.tryRemoveFile(this.configFilePath);\n new TextFile(this, this.configFilePath, {\n lines: this.renderConfig(),\n });\n }\n}\n\nfunction renderImport(spec: AstroIntegrationSpec): string {\n const asDefault = spec.defaultImport ?? true;\n const binding = asDefault ? spec.name : `{ ${spec.name} }`;\n return `import ${binding} from ${JSON.stringify(spec.importPath)};`;\n}\n\nfunction renderCall(spec: AstroIntegrationSpec): string {\n return `${spec.name}(${spec.args ?? \"\"})`;\n}\n","/**\n * Astro output mode.\n *\n * @see https://docs.astro.build/en/reference/configuration-reference/#output\n */\nexport const AstroOutput = {\n STATIC: \"static\",\n SERVER: \"server\",\n HYBRID: \"hybrid\",\n} as const;\n\nexport type AstroOutput = (typeof AstroOutput)[keyof typeof AstroOutput];\n\n/**\n * Declarative spec for an Astro integration or adapter import.\n *\n * Rendered into `astro.config.mjs` as an import plus an invocation in\n * the `integrations` array (or as the `adapter` field).\n */\nexport interface AstroIntegrationSpec {\n /**\n * Local binding used in the generated config, e.g. \"react\".\n */\n readonly name: string;\n\n /**\n * Module to import from, e.g. \"@astrojs/react\".\n */\n readonly importPath: string;\n\n /**\n * Raw argument expression passed to the integration call.\n *\n * Written verbatim inside the parentheses, e.g. `\"{ include: ['**\\/*.tsx'] }\"`.\n * When omitted the integration is invoked with no arguments.\n */\n readonly args?: string;\n\n /**\n * When true, use a default import (`import name from ...`).\n * When false or omitted, use a named import (`import { name } from ...`).\n *\n * @default true\n */\n readonly defaultImport?: boolean;\n}\n\n/**\n * Options controlling the rendered `astro.config.mjs`.\n */\nexport interface AstroConfigOptions {\n /**\n * Site URL (used for canonical URLs, sitemaps, RSS).\n */\n readonly site?: string;\n\n /**\n * Base path the site is deployed under.\n */\n readonly base?: string;\n\n /**\n * Output mode.\n *\n * @default AstroOutput.STATIC\n */\n readonly output?: AstroOutput;\n\n /**\n * Integrations rendered into the `integrations` array.\n */\n readonly integrations?: Array<AstroIntegrationSpec>;\n\n /**\n * SSR adapter rendered into the `adapter` field.\n */\n readonly adapter?: AstroIntegrationSpec;\n}\n","import { join, relative } from \"node:path\";\n// eslint-disable-next-line import/no-extraneous-dependencies\nimport { AWS_STAGE_TYPE } from \"@codedrifters/utils\";\nimport { Component } from \"projen\";\nimport { AwsCdkTypeScriptApp } from \"projen/lib/awscdk\";\nimport { AwsDeploymentTarget } from \"./aws-deployment-target\";\nimport { TurboRepo } from \"../turbo\";\n\n/*******************************************************************************\n *\n * AWS Deployment Configuration\n *\n * This component allows configuration of multiple AWS deployment\n * targets, each with its own account, region, and deployment type\n * (dev, stage, prod). It supports both local and CI deployments,\n * with customizable settings for each target.\n *\n ******************************************************************************/\n\n/*\nexport interface AwsDeploymentConfigOptions {}\n*/\n\nexport class AwsDeploymentConfig extends Component {\n public static of(\n project: AwsCdkTypeScriptApp,\n ): AwsDeploymentConfig | undefined {\n const isDefined = (c: Component): c is AwsDeploymentConfig =>\n c instanceof AwsDeploymentConfig;\n return project.components.find(isDefined);\n }\n\n /**\n * Environment variables to be injected into all tasks.\n */\n public readonly env: Record<string, string>;\n\n /**\n * The relative path to the project directory from the root of the project.\n */\n public readonly projectPath: string;\n\n /**\n * The relative path to the root of the project from the output directory.\n */\n public readonly rootPath: string;\n\n /**\n * The output directory for the CDK synthesis, from the root directory.\n */\n public readonly rootCdkOut: string;\n\n /**\n * The output directory for the CDK synthesis.\n */\n public readonly cdkOut: string;\n\n /**\n * Array of targets for deployment.\n */\n public readonly awsDeploymentTargets: Array<AwsDeploymentTarget> = [];\n\n constructor(project: AwsCdkTypeScriptApp) {\n super(project);\n\n /**\n * Common variables used across tasks.\n * Value must be exactly $(...) so Projen's task runtime expands it (evalEnvironment\n * only substitutes when the full value matches $(...)); the shell then expands\n * ${GIT_BRANCH_NAME:-$(git branch --show-current)} to the current branch or existing env.\n */\n this.env = {\n GIT_BRANCH_NAME:\n '$(echo \"${GIT_BRANCH_NAME:-$(git branch --show-current)}\")',\n };\n this.projectPath = relative(project.root.outdir, project.outdir);\n this.rootPath = relative(project.outdir, project.root.outdir);\n this.rootCdkOut = join(\"dist\", this.projectPath, \"cdk.out\");\n this.cdkOut = join(this.rootPath, \"dist\", this.projectPath, \"cdk.out\");\n\n /**\n * Reset some tasks we will rebuild below.\n */\n [\"deploy\", \"watch\"].forEach((taskName) => {\n const task = project.tasks.tryFind(taskName);\n if (task) {\n task.reset();\n task.say(\n \"Generic task is disabled. Please use the specific task for your deployment target.\",\n );\n }\n });\n\n /**\n * Redefine Synth here\n *\n * Deploy and watch get reconfigured per deployment target.\n * @see addDeploymentTarget()\n */\n this.configureSynthTask();\n }\n\n /*****************************************************************************\n *\n * Target filter helpers\n *\n * Return various targets for deployment scripts to use.\n *\n ****************************************************************************/\n\n /**\n * @returns All production deployment targets.\n */\n public get prodTargets(): Array<AwsDeploymentTarget> {\n return this.awsDeploymentTargets.filter(\n (target) => target.awsStageType === AWS_STAGE_TYPE.PROD,\n );\n }\n public get prodTargetsForCI(): Array<AwsDeploymentTarget> {\n return this.awsDeploymentTargets.filter(\n (target) =>\n target.awsStageType === AWS_STAGE_TYPE.PROD && target.ciDeployment,\n );\n }\n public get prodTargetsForLocal(): Array<AwsDeploymentTarget> {\n return this.awsDeploymentTargets.filter(\n (target) =>\n target.awsStageType === AWS_STAGE_TYPE.PROD && target.localDeployment,\n );\n }\n\n /**\n *\n * @returns All stage deployment targets.\n */\n public get stageTargets(): Array<AwsDeploymentTarget> {\n return this.awsDeploymentTargets.filter(\n (target) => target.awsStageType === AWS_STAGE_TYPE.STAGE,\n );\n }\n public get stageTargetsForCI(): Array<AwsDeploymentTarget> {\n return this.awsDeploymentTargets.filter(\n (target) =>\n target.awsStageType === AWS_STAGE_TYPE.STAGE && target.ciDeployment,\n );\n }\n public get stageTargetsForLocal(): Array<AwsDeploymentTarget> {\n return this.awsDeploymentTargets.filter(\n (target) =>\n target.awsStageType === AWS_STAGE_TYPE.STAGE && target.localDeployment,\n );\n }\n\n /**\n *\n * @returns All dev deployment targets.\n */\n public get devTargets(): Array<AwsDeploymentTarget> {\n return this.awsDeploymentTargets.filter(\n (target) => target.awsStageType === AWS_STAGE_TYPE.DEV,\n );\n }\n public get devTargetsForCI(): Array<AwsDeploymentTarget> {\n return this.awsDeploymentTargets.filter(\n (target) =>\n target.awsStageType === AWS_STAGE_TYPE.DEV && target.ciDeployment,\n );\n }\n public get devTargetsForLocal(): Array<AwsDeploymentTarget> {\n return this.awsDeploymentTargets.filter(\n (target) =>\n target.awsStageType === AWS_STAGE_TYPE.DEV && target.localDeployment,\n );\n }\n\n /*****************************************************************************\n *\n * Synth Tasks\n *\n * - Configure synth task to use the branch name\n * - Change the output location for easier workflows.\n *\n ****************************************************************************/\n\n private configureSynthTask = (): void => {\n this.project.tasks.tryFind(\"synth\")?.reset(`rm -rf ${this.cdkOut}`);\n this.project.tasks\n .tryFind(\"synth\")\n ?.exec(`cdk synth --output ${this.cdkOut}`, { env: this.env });\n\n this.project.tasks.tryFind(\"synth:silent\")?.reset(`rm -rf ${this.cdkOut}`);\n this.project.tasks\n .tryFind(\"synth:silent\")\n ?.exec(`cdk synth -q --output ${this.cdkOut}`, { env: this.env });\n };\n\n preSynthesize(): void {\n super.preSynthesize();\n\n /**\n * If turbo's active we should ensure the post compile task\n * is configured to consider the cdk output directory in it's root location.\n */\n if (TurboRepo.of(this.project)) {\n const turbo = TurboRepo.of(this.project)!;\n turbo.postCompileTask?.outputs.push(join(this.cdkOut, \"**\"));\n }\n }\n}\n","// eslint-disable-next-line import/no-extraneous-dependencies\nimport {\n AWS_STAGE_TYPE,\n AwsEnvironmentType,\n AwsStageType,\n DEPLOYMENT_TARGET_ROLE,\n DeploymentTargetRoleType,\n} from \"@codedrifters/utils\";\nimport { Component } from \"projen\";\nimport { AwsCdkTypeScriptApp } from \"projen/lib/awscdk\";\nimport { AwsDeploymentConfig } from \"./aws-deployment-config\";\nimport { GitBranch } from \"../git\";\n\n/*******************************************************************************\n *\n * AWS Deployment Configuration\n *\n * A single deployment target that CDK applications can be deployed into.\n *\n ******************************************************************************/\n\n/**\n * Represents the configuration for local deployment in AWS.\n */\nexport interface AwsLocalDeploymentConfig {\n /**\n * The AWS profile (in ~/.aws/config) to use for local deployment.\n *\n * @default generated dynamically based role name, account and region\n */\n readonly profile?: string;\n\n /**\n * Named Role used to conduct local deployments.\n *\n * @default \"poweruseraccess\"\n */\n readonly roleName?: string;\n\n /**\n * The pattern used to identify stacks to deploy in CI deployments.\n *\n * @default *-${account}-${region}\n */\n readonly stackPattern?: string;\n}\n\nexport interface CiDeploymentConfig {\n /**\n * The OIDC IAM Role to assume for CI deployments.\n */\n readonly roleArn: string;\n\n /**\n * The pattern used to identify stacks to deploy in CI deployments.\n *\n * @default *-${account}-${region}\n */\n readonly stackPattern?: string;\n}\n\n/**\n * Represents a deployment target in AWS, including account and region, and\n * branches allowed to deploy to this target.\n */\nexport interface AwsDeploymentTargetOptions {\n /**\n * The account name for the deployment target.\n */\n readonly account: string;\n\n /**\n * The AWS region for the deployment target.\n */\n readonly region: string;\n\n /**\n * AWS deployment type, such as dev, stage, or prod.\n *\n * @default 'dev'\n */\n readonly awsStageType?: AwsStageType;\n\n /**\n * Deployment target role: whether this (account, region) is the primary or\n * secondary deployment target (e.g. primary vs replica region).\n *\n * @default 'primary'\n */\n readonly deploymentTargetRole?: DeploymentTargetRoleType;\n\n /**\n * AWS environment type, such as primary or secondary.\n *\n * @deprecated Use `deploymentTargetRole` instead. This property is maintained for backward compatibility.\n * @default 'primary'\n */\n readonly awsEnvironmentType?: AwsEnvironmentType;\n\n /**\n * The AWS profile to use for this deployment target.\n *\n * @default ['main'] when prod release type, ['feature/*'] when dev type\n */\n readonly branches?: Array<GitBranch>;\n\n /**\n * Can this deployment target be used for local development?\n *\n * @default true for dev environments, false for prod environments\n */\n readonly localDeployment?: boolean;\n\n /**\n * Configuration when deploying to this target locally.\n */\n readonly localDeploymentConfig?: AwsLocalDeploymentConfig;\n\n /**\n * Can this deployment target be used in CI deployments?\n *\n * @default false\n */\n readonly ciDeployment?: boolean;\n\n /*\n * Configuration when deploying to this target in CI.\n\n */\n readonly ciDeploymentConfig?: CiDeploymentConfig;\n}\n\nexport class AwsDeploymentTarget extends Component {\n /**\n * Static method to discovert targets in a project.\n */\n public static of(\n project: AwsCdkTypeScriptApp,\n ): Array<AwsDeploymentTarget> | undefined {\n const isDefined = (c: Component): c is AwsDeploymentTarget =>\n c instanceof AwsDeploymentTarget;\n return project.components.filter(isDefined);\n }\n\n /**\n * The account name for the deployment target.\n */\n public account: string;\n\n /**\n * The AWS region for the deployment target.\n */\n public region: string;\n\n /**'\n * AWS stage type, such as dev, stage, or prod.\n *\n * @default 'dev'\n */\n public awsStageType: AwsStageType;\n\n /**\n * Deployment target role: whether this (account, region) is the primary or\n * secondary deployment target (e.g. primary vs replica region).\n *\n * @default 'primary'\n */\n public deploymentTargetRole: DeploymentTargetRoleType;\n\n /**\n * AWS environment type, such as primary or secondary.\n *\n * @deprecated Use `deploymentTargetRole` instead. This property is maintained for backward compatibility.\n * @default 'primary'\n */\n public awsEnvironmentType: AwsEnvironmentType;\n\n /**\n * The AWS profile to use for this deployment target.\n *\n * @default ['main'] when prod release type, ['feature/*'] when dev type\n */\n public branches: Array<GitBranch> = [];\n\n /**\n * Can this deployment target be used for local development?\n *\n * @default true for dev environments, false for prod environments\n */\n public localDeployment?: boolean;\n\n /**\n * Configuration when deploying to this target locally.\n */\n public localDeploymentConfig?: AwsLocalDeploymentConfig;\n\n /**\n * Can this deployment target be used in CI deployments?\n *\n * @default false\n */\n public ciDeployment?: boolean;\n\n /*\n * Configuration when deploying to this target in CI.\n */\n public ciDeploymentConfig?: Required<CiDeploymentConfig>;\n\n /**\n * Configuration for the CDK output directory for this deployment target.\n */\n public awsDeploymentConfig: AwsDeploymentConfig;\n\n constructor(\n project: AwsCdkTypeScriptApp,\n options: AwsDeploymentTargetOptions,\n ) {\n super(project);\n\n /**\n * Set target region and account.\n */\n this.account = options.account;\n this.region = options.region;\n\n /**\n * Set default type\n */\n this.awsStageType = options.awsStageType || AWS_STAGE_TYPE.DEV;\n\n /**\n * Set deployment target role (preferred) or fall back to deprecated awsEnvironmentType.\n */\n const role =\n options.deploymentTargetRole ??\n options.awsEnvironmentType ??\n DEPLOYMENT_TARGET_ROLE.PRIMARY;\n this.deploymentTargetRole = role;\n this.awsEnvironmentType = role;\n\n /**\n * Set default Branches\n */\n\n this.branches =\n options.branches ??\n (this.awsStageType === AWS_STAGE_TYPE.PROD\n ? [\n {\n branch: \"main\",\n },\n ]\n : [\n {\n branch: \"feature/*\",\n },\n ]);\n\n /**\n * Set default for local deployment\n */\n this.localDeployment =\n options.localDeployment ?? this.awsStageType === AWS_STAGE_TYPE.DEV;\n\n /**\n * Some default configurations for local deployments.\n */\n if (this.localDeployment) {\n const roleName =\n options.localDeploymentConfig?.roleName?.toLowerCase() ||\n \"poweruseraccess\";\n const profile =\n options.localDeploymentConfig?.profile ||\n `${roleName}-${this.awsStageType}-${this.account}-${this.region}`;\n\n const stackPattern =\n options.localDeploymentConfig?.stackPattern ||\n `${this.awsStageType}/${this.awsEnvironmentType}/*-${this.account}-${this.region}`;\n\n this.localDeploymentConfig = {\n profile,\n roleName,\n stackPattern,\n ...options.localDeploymentConfig,\n };\n }\n\n /**\n * Set CI deployment default\n */\n this.ciDeployment = options.ciDeployment ?? false;\n\n /**\n * Some defaults for CI deployments.\n */\n if (this.ciDeployment) {\n const roleArn =\n options.ciDeploymentConfig?.roleArn ||\n `arn:aws:iam::${this.account}:role/GitHubDeployer}`;\n\n const stackPattern =\n options.ciDeploymentConfig?.stackPattern ||\n `${this.awsStageType}/${this.awsEnvironmentType}/*-${this.account}-${this.region}`;\n\n this.ciDeploymentConfig = {\n roleArn,\n stackPattern,\n ...options.ciDeploymentConfig,\n };\n }\n\n /**\n * Find or create CDK folder config for this project.\n */\n this.awsDeploymentConfig =\n AwsDeploymentConfig.of(project) || new AwsDeploymentConfig(project);\n\n /**\n * Add the target to the deployment targets array.\n */\n this.awsDeploymentConfig.awsDeploymentTargets.push(this);\n\n // Deploy tasks are configured per target.\n this.configureDeployTask();\n\n // Watch tasks are configured per target.\n this.configureWatchTask();\n }\n\n /*****************************************************************************\n *\n * Deploy Tasks\n *\n * - If local deploy, add a deploy task.\n *\n ****************************************************************************/\n\n private configureDeployTask = (): void => {\n if (this.localDeployment) {\n const taskName = [\n \"deploy\",\n this.awsStageType,\n this.account,\n this.region,\n ].join(\":\");\n const deployTask = this.project.tasks.addTask(taskName, {\n env: this.awsDeploymentConfig.env,\n });\n deployTask.exec(\n `cdk deploy --lookups=false --require-approval=never --profile=${this.localDeploymentConfig?.profile} --app=${this.awsDeploymentConfig.cdkOut} \"${this.localDeploymentConfig?.stackPattern}\"`,\n );\n }\n };\n\n /*****************************************************************************\n *\n * Watch tasks\n *\n * - Configure watch task to use the branch name\n * - configure watch task to use the correct synth output location.\n *\n ****************************************************************************/\n\n private configureWatchTask = (): void => {\n if (this.localDeployment) {\n const taskName = [\n \"watch\",\n this.awsStageType,\n this.account,\n this.region,\n ].join(\":\");\n const watchTask = this.project.tasks.addTask(taskName, {\n env: this.awsDeploymentConfig.env,\n });\n\n // update the synth first\n const synthSilent = this.project.tasks.tryFind(\"synth:silent\");\n if (synthSilent) {\n watchTask.spawn(synthSilent);\n }\n\n // do a normal deploy\n watchTask.exec(\n `cdk deploy --lookups=false --require-approval=never --profile=${this.localDeploymentConfig?.profile} --app=${this.awsDeploymentConfig.cdkOut} \"${this.localDeploymentConfig?.stackPattern}\"`,\n );\n\n // watch for changes and log output\n watchTask.exec(\n `cdk watch --lookups=false --require-approval=never --hotswap --profile=${this.localDeploymentConfig?.profile} \"${this.localDeploymentConfig?.stackPattern}\"`,\n );\n }\n };\n}\n","const NPM_REGISTRY = \"https://registry.npmjs.org\";\n\n/**\n * Metadata for a package from the npm registry. Only the fields we use are typed.\n *\n * @see https://github.com/npm/registry/blob/master/docs/responses/package-metadata.md\n */\ninterface NpmPackageMetadata {\n name?: string;\n \"dist-tags\"?: { latest?: string };\n time?: Record<string, string>;\n versions?: Record<string, unknown>;\n}\n\n/**\n * Returns true if the version has a semver prerelease segment (e.g. -canary, -alpha, -beta).\n * Full releases like 1.2.3 or 1.2.3+build.1 return false.\n */\nfunction isPrerelease(version: string): boolean {\n const v = version.replace(/^v/, \"\");\n return /^\\d+\\.\\d+\\.\\d+-/.test(v);\n}\n\n/**\n * Compares two semver-like version strings (e.g. \"1.2.3\").\n * Returns negative if a < b, positive if a > b, 0 if equal.\n * Prerelease segments are treated as less than release.\n */\nfunction compareVersions(a: string, b: string): number {\n const parse = (v: string): number[] => {\n const parts = v.replace(/^v/, \"\").split(/[-+]/)[0].split(\".\");\n return parts.map((p) => {\n const n = parseInt(p, 10);\n return Number.isNaN(n) ? 0 : n;\n });\n };\n const pa = parse(a);\n const pb = parse(b);\n const len = Math.max(pa.length, pb.length);\n for (let i = 0; i < len; i++) {\n const na = pa[i] ?? 0;\n const nb = pb[i] ?? 0;\n if (na !== nb) return na - nb;\n }\n return 0;\n}\n\n/**\n * Returns the latest full-release version of an npm package that has been\n * published for at least `minimumReleaseAgeMinutes` minutes. Prefers the\n * version indicated by the registry's \"latest\" dist-tag when it is a full\n * release: if that version's publish time is in the registry and old enough,\n * it is used; if it is not in the registry's \"time\" object (e.g. truncated\n * for large packages), the dist-tag is still used so npm's \"latest\" is\n * followed. When the dist-tag version is too new (in time but not old enough),\n * we fall back to the highest full-release version that is old enough and\n * ≤ latest (e.g. latest 2.x that's old enough, not 3.0.0). Prerelease\n * versions are excluded. Returns null if `time` is missing or no version is\n * eligible.\n *\n * @param packageName - npm package name (e.g. \"projen\").\n * @param minimumReleaseAgeMinutes - minimum age in minutes (e.g. 1440 for 24h).\n * @returns The latest eligible version string, or null.\n */\nexport async function getLatestEligibleVersion(\n packageName: string,\n minimumReleaseAgeMinutes: number,\n): Promise<string | null> {\n const url = `${NPM_REGISTRY}/${encodeURIComponent(packageName)}`;\n let res: Response;\n try {\n res = await fetch(url, {\n headers: { Accept: \"application/json\" },\n });\n } catch {\n return null;\n }\n if (!res.ok) return null;\n let data: NpmPackageMetadata;\n try {\n data = (await res.json()) as NpmPackageMetadata;\n } catch {\n return null;\n }\n const time = data.time;\n if (!time || typeof time !== \"object\") return null;\n\n const nowMs = Date.now();\n const minAgeMs = minimumReleaseAgeMinutes * 60 * 1000;\n\n const distTagLatest = data[\"dist-tags\"]?.latest;\n if (distTagLatest && !isPrerelease(distTagLatest)) {\n const publishedAtStr = time[distTagLatest];\n if (typeof publishedAtStr === \"string\") {\n const publishedAt = Date.parse(publishedAtStr);\n if (!Number.isNaN(publishedAt) && nowMs - publishedAt >= minAgeMs) {\n return distTagLatest;\n }\n } else {\n return distTagLatest;\n }\n }\n\n const versionTimestamps: { version: string; publishedAt: number }[] = [];\n for (const [key, value] of Object.entries(time)) {\n if (key === \"created\" || key === \"modified\" || typeof value !== \"string\") {\n continue;\n }\n if (isPrerelease(key)) continue;\n const publishedAt = Date.parse(value);\n if (Number.isNaN(publishedAt)) continue;\n const ageMs = nowMs - publishedAt;\n if (ageMs >= minAgeMs) {\n versionTimestamps.push({ version: key, publishedAt });\n }\n }\n\n if (versionTimestamps.length === 0) return null;\n\n let candidates = versionTimestamps;\n if (distTagLatest && !isPrerelease(distTagLatest)) {\n candidates = versionTimestamps.filter(\n (e) => compareVersions(e.version, distTagLatest) <= 0,\n );\n }\n if (candidates.length === 0) return null;\n\n candidates.sort((a, b) => compareVersions(b.version, a.version));\n return candidates[0].version;\n}\n","import { VERSION } from \"./versions\";\n\n/**\n * Keys of the VERSION object in versions.ts.\n */\nexport type VersionKey = keyof typeof VERSION;\n\n/**\n * Mapping of VERSION keys that are backed by an npm package and eligible\n * for auto-update. Only these keys should be updated by version-update\n * automation; others (e.g. NODE_WORKFLOWS) are skipped.\n *\n * @see {@link VERSION_KEYS_SKIP} for keys that must not be auto-updated.\n */\nexport const VERSION_NPM_PACKAGES: ReadonlyArray<{\n key: VersionKey;\n npmPackage: string;\n}> = [\n { key: \"ASTRO_VERSION\", npmPackage: \"astro\" },\n { key: \"AWS_CDK_CLI_VERSION\", npmPackage: \"aws-cdk\" },\n { key: \"AWS_CDK_LIB_VERSION\", npmPackage: \"aws-cdk-lib\" },\n { key: \"AWS_CONSTRUCTS_VERSION\", npmPackage: \"constructs\" },\n { key: \"PNPM_VERSION\", npmPackage: \"pnpm\" },\n { key: \"PROJEN_VERSION\", npmPackage: \"projen\" },\n { key: \"SHARP_VERSION\", npmPackage: \"sharp\" },\n { key: \"STARLIGHT_VERSION\", npmPackage: \"@astrojs/starlight\" },\n { key: \"TURBO_VERSION\", npmPackage: \"turbo\" },\n { key: \"TYPES_NODE_VERSION\", npmPackage: \"@types/node\" },\n { key: \"VITEST_VERSION\", npmPackage: \"vitest\" },\n] as const;\n\n/**\n * VERSION keys that are not backed by npm or must be skipped by\n * auto-update (e.g. runtime versions like Node.js, or pinned deps like\n * VITE_VERSION until ESM-only test setup).\n */\nexport const VERSION_KEYS_SKIP: ReadonlyArray<VersionKey> = [\n \"NODE_WORKFLOWS\",\n \"VITE_VERSION\",\n \"VITEST_VERSION\", // Pinned to 3.x for Vite 5 compatibility; skip until ESM-only (issue #142)\n];\n","import * as spec from \"@jsii/spec\";\nimport { Component, JsonFile } from \"projen\";\nimport { TypeScriptProject } from \"projen/lib/typescript\";\nimport { ValueOf } from \"type-fest\";\n\n/**\n * The FQNs for the base classes and options used by Jsii.\n *\n * These are the defaults used by Projen's TypeScriptProject.\n */\nconst ProjenBaseFqn = {\n TYPESCRIPT_PROJECT: \"projen.typescript.TypeScriptProject\",\n TYPESCRIPT_PROJECT_OPTIONS: \"projen.typescript.TypeScriptProjectOptions\",\n} as const;\n\nexport interface ClassTypeOptions {\n /**\n * The name of the class.\n *\n * @example \"MyProject\"\n */\n name: string;\n\n /**\n * The FQN for the base class this class is extending.\n *\n * @default ProjenBaseFqn.TYPESCRIPT_PROJECT\n */\n baseFqn?: ValueOf<typeof ProjenBaseFqn> | string;\n\n /**\n * The FQN for the options for this class.\n *\n * @default ProjenBaseFqn.TYPESCRIPT_PROJECT_OPTIONS\n */\n optionsFqn?: ValueOf<typeof ProjenBaseFqn> | string;\n}\n\nexport class JsiiFaker extends Component {\n // find project singleton\n public static of(project: TypeScriptProject): JsiiFaker | undefined {\n const isDefined = (c: Component): c is JsiiFaker => c instanceof JsiiFaker;\n return project.components.find(isDefined);\n }\n\n private _assemblyName: string;\n private _types: { [name: string]: spec.Type } = {};\n\n constructor(public readonly project: TypeScriptProject) {\n super(project);\n\n /**\n * In JSII, the assembly name is essentially the package name. It's used as a\n * scope when targeting types and metadata in other \"jsii assemblies\" that\n * might be in sub-packages used by the project.\n *\n * For this case, we'll just use the package name from Projen.\n */\n this._assemblyName = this.project.package.packageName;\n\n new JsonFile(project, \".jsii\", {\n obj: () => {\n return {\n name: this._assemblyName,\n types: this._types,\n };\n },\n });\n }\n\n public toJSON = () => {\n return {\n types: this._types,\n };\n };\n\n public addClassType(options: ClassTypeOptions) {\n const fqn = [this._assemblyName, options.name].join(\".\");\n const type: spec.ClassType = {\n assembly: this._assemblyName,\n base: options.baseFqn ?? ProjenBaseFqn.TYPESCRIPT_PROJECT,\n fqn,\n kind: spec.TypeKind.Class,\n name: options.name,\n initializer: {\n parameters: [\n {\n name: \"options\",\n type: {\n fqn:\n options.optionsFqn ?? ProjenBaseFqn.TYPESCRIPT_PROJECT_OPTIONS,\n },\n },\n ],\n },\n };\n\n this._types[fqn] = type;\n }\n}\n","import { SampleFile } from \"projen\";\nimport { AstroConfig } from \"../astro/astro-config\";\nimport {\n AstroConfigOptions,\n AstroIntegrationSpec,\n} from \"../astro/astro-config-options\";\nimport { TurboRepo } from \"../turbo\";\nimport { VERSION } from \"../versions\";\nimport {\n TestRunner,\n TypeScriptProject,\n TypeScriptProjectOptions,\n} from \"./typescript-project\";\n\n/**\n * Configuration options for AstroProject.\n */\nexport interface AstroProjectOptions\n extends TypeScriptProjectOptions, AstroConfigOptions {\n /**\n * Astro package version.\n *\n * @default VERSION.ASTRO_VERSION\n */\n readonly astroVersion?: string;\n\n /**\n * Emit sample Astro starter files (`src/pages/index.astro`, `public/favicon.svg`).\n *\n * @default false\n */\n readonly sampleCode?: boolean;\n\n /**\n * Astro tsconfig preset to extend.\n *\n * @default \"astro/tsconfigs/strict\"\n */\n readonly astroTsconfigExtends?: string;\n}\n\n/**\n * Minimal Astro site scaffolded on top of {@link TypeScriptProject}.\n *\n * Replaces the `tsc` compile step with `astro check && astro build`, writes\n * `astro.config.mjs`, sets `\"type\": \"module\"`, and wires dev/preview tasks.\n */\nexport class AstroProject extends TypeScriptProject {\n /**\n * Rendered Astro config component.\n */\n public readonly astroConfig: AstroConfig;\n\n constructor(userOptions: AstroProjectOptions) {\n /**\n * Default to Vitest — Astro's native test runner — and exclude `astro`\n * from projen's per-package ncu upgrade workflow so only the\n * configulator VERSION-driven update path owns it.\n */\n const options: AstroProjectOptions = {\n testRunner: TestRunner.VITEST,\n ...userOptions,\n depsUpgradeOptions: {\n ...userOptions.depsUpgradeOptions,\n exclude: [...(userOptions.depsUpgradeOptions?.exclude ?? []), \"astro\"],\n },\n };\n\n super(options);\n\n const astroVersion = options.astroVersion ?? VERSION.ASTRO_VERSION;\n const astroTsconfigExtends =\n options.astroTsconfigExtends ?? \"astro/tsconfigs/strict\";\n\n /**\n * Astro ships as ESM; the site package must be a module.\n */\n this.package.addField(\"type\", \"module\");\n\n /**\n * Extend Astro's tsconfig preset so `astro check` and IDE tooling\n * understand `.astro` files, JSX, and bundler-style resolution.\n */\n this.tsconfig?.file.addOverride(\"extends\", astroTsconfigExtends);\n this.tsconfig?.addInclude(\".astro/types.d.ts\");\n this.tsconfig?.addInclude(\"src/**/*.astro\");\n\n /**\n * Replace projen's tsc-driven compile with Astro's build pipeline.\n */\n this.compileTask.reset();\n this.compileTask.exec(\"astro check\");\n this.compileTask.exec(\"astro build\");\n\n /**\n * Point `watch` at Astro's dev server (projen's default runs `tsc -w`,\n * which is meaningless for an Astro site).\n */\n this.tasks.tryFind(\"watch\")?.reset(\"astro dev\");\n\n /**\n * A website is not an npm tarball — reset `package` to a no-op so the\n * inherited `build` task does not emit `dist/js/*.tgz` alongside the\n * actual site output.\n */\n this.packageTask.reset();\n\n /**\n * Astro CLI tasks. `build` already exists on projen; add only the\n * Astro-specific lifecycle tasks.\n */\n if (!this.tasks.tryFind(\"dev\")) {\n this.addTask(\"dev\", {\n description: \"Start the Astro dev server\",\n exec: \"astro dev\",\n receiveArgs: true,\n });\n }\n if (!this.tasks.tryFind(\"preview\")) {\n this.addTask(\"preview\", {\n description: \"Preview the built site locally\",\n exec: \"astro preview\",\n receiveArgs: true,\n });\n }\n if (!this.tasks.tryFind(\"check\")) {\n this.addTask(\"check\", {\n description: \"Run Astro's type and content checks\",\n exec: \"astro check\",\n });\n }\n\n /**\n * Runtime and tooling dependencies.\n */\n this.addDeps(`astro@${astroVersion}`);\n this.addDevDeps(\n \"@astrojs/check\",\n \"astro-eslint-parser\",\n \"eslint-plugin-astro\",\n \"prettier-plugin-astro\",\n );\n\n /**\n * Register the Astro prettier plugin so `.astro` files are formatted.\n */\n const prettierConfig = this.tryFindObjectFile(\".prettierrc.json\");\n prettierConfig?.addOverride(\"plugins\", [\"prettier-plugin-astro\"]);\n prettierConfig?.addOverride(\"overrides\", [\n { files: \"*.astro\", options: { parser: \"astro\" } },\n ]);\n\n /**\n * Wire eslint-plugin-astro so `.astro` files are actually linted.\n * Projen's default `fileExtensions` is constructor-only and set to `.ts`,\n * so we add an explicit lint pattern to force `.astro` paths onto the\n * generated eslint command line.\n */\n this.eslint?.addPlugins(\"astro\");\n this.eslint?.addExtends(\"plugin:astro/recommended\");\n this.eslint?.addOverride({\n files: [\"*.astro\"],\n parser: \"astro-eslint-parser\",\n });\n this.eslint?.addLintPattern(\"src/**/*.astro\");\n\n /**\n * Astro-specific gitignore entries. `dist` is already handled by the\n * base TypeScriptProject.\n */\n this.gitignore.addPatterns(\".astro\", \".vercel\", \".netlify\");\n\n /**\n * Extend turbo inputs so the compile task invalidates on Astro-specific\n * source paths. Outputs (`dist/**`) are already added by the base class.\n */\n const turbo = TurboRepo.of(this);\n if (turbo?.compileTask) {\n turbo.compileTask.inputs.push(\"public/**\", \"astro.config.mjs\");\n }\n\n /**\n * Render astro.config.mjs.\n */\n const integrations: Array<AstroIntegrationSpec> =\n options.integrations ?? [];\n this.astroConfig = new AstroConfig(this, {\n site: options.site,\n base: options.base,\n output: options.output,\n integrations,\n adapter: options.adapter,\n });\n\n /**\n * Optional starter files.\n */\n if (options.sampleCode === true) {\n new SampleFile(this, \"src/pages/index.astro\", {\n contents: DEFAULT_INDEX_ASTRO,\n });\n new SampleFile(this, \"public/favicon.svg\", {\n contents: DEFAULT_FAVICON_SVG,\n });\n }\n }\n}\n\nconst DEFAULT_INDEX_ASTRO = `---\n// Welcome to Astro!\n---\n<html lang=\"en\">\n <head>\n <meta charset=\"utf-8\" />\n <link rel=\"icon\" type=\"image/svg+xml\" href=\"/favicon.svg\" />\n <meta name=\"viewport\" content=\"width=device-width\" />\n <title>Astro</title>\n </head>\n <body>\n <h1>Hello, Astro!</h1>\n </body>\n</html>\n`;\n\nconst DEFAULT_FAVICON_SVG = `<svg xmlns=\"http://www.w3.org/2000/svg\" viewBox=\"0 0 128 128\"><path d=\"M64 8a56 56 0 1 0 0 112A56 56 0 0 0 64 8Z\" fill=\"#ff5d01\"/></svg>\n`;\n","import { typescript } from \"projen\";\nimport {\n NodePackageManager,\n Transform,\n UpgradeDependenciesSchedule,\n} from \"projen/lib/javascript\";\nimport { ReleaseTrigger } from \"projen/lib/release\";\nimport { merge } from \"ts-deepmerge\";\nimport { MonorepoProject } from \"./monorepo-project\";\nimport { AgentConfig } from \"../agent/agent-config\";\nimport { AgentConfigOptions } from \"../agent/agent-config-options\";\nimport { PnpmWorkspace } from \"../pnpm\";\nimport { ResetTask, ResetTaskOptions } from \"../tasks/reset-task\";\nimport { TurboRepo } from \"../turbo\";\nimport { Vitest, VitestOptions } from \"../vitest\";\n\n/**\n * Test runner for TypeScript projects.\n */\nexport const TestRunner = {\n JEST: \"jest\",\n VITEST: \"vitest\",\n} as const;\n\nexport type TestRunner = (typeof TestRunner)[keyof typeof TestRunner];\n\n/**\n * Configuration options for TypeScriptProject.\n */\nexport interface TypeScriptProjectOptions extends Omit<\n typescript.TypeScriptProjectOptions,\n \"defaultReleaseBranch\"\n> {\n /**\n * Test runner to use.\n *\n * @default TestRunner.JEST\n */\n readonly testRunner?: TestRunner;\n\n /**\n * Options for Vitest (only used when testRunner is 'vitest').\n */\n readonly vitestOptions?: VitestOptions;\n\n /**\n * Enable the reset task that deletes all build artifacts.\n *\n * @default true\n */\n readonly resetTask?: boolean;\n\n /**\n * Options for the reset task.\n */\n readonly resetTaskOptions?: ResetTaskOptions;\n\n /**\n * AI agent configuration (Cursor, Claude Code rules).\n * Generates rule files with auto-detected bundles based on project tooling.\n *\n * - `true` or `{}`: enable with auto-detected defaults\n * - `AgentConfigOptions`: enable with explicit configuration\n * - `false` or `undefined`: disabled (default)\n *\n * Sub-projects do not inherit `AgentConfig` from their parent\n * `MonorepoProject`. Agent rule files are rendered only on projects that\n * explicitly opt in, so a monorepo's root `AgentConfig` does not duplicate\n * `.cursor/`, `.claude/`, or `CLAUDE.md` into each sub-project's `outdir`.\n *\n * @default false\n */\n readonly agentConfig?: AgentConfigOptions | boolean;\n}\n\nexport class TypeScriptProject extends typescript.TypeScriptProject {\n constructor(userOptions: TypeScriptProjectOptions) {\n /**\n * Configulator requires every project to live inside a MonorepoProject.\n * The catalog-based @types/node pin and the workspace install hook both\n * assume the parent exists.\n */\n if (!(userOptions.parent instanceof MonorepoProject)) {\n throw new Error(\n \"TypeScriptProject must be parented to a MonorepoProject. Pass `parent: <MonorepoProject>` in the project options.\",\n );\n }\n\n const parent = userOptions.parent;\n const pnpmVersion = parent.pnpmVersion;\n const pnpmWorkspace = PnpmWorkspace.of(parent);\n\n /*************************************************************************\n *\n * Default Options\n *\n ************************************************************************/\n\n const testRunner = userOptions.testRunner ?? TestRunner.JEST;\n const useJest = testRunner === TestRunner.JEST;\n\n const defaultOptions: Omit<TypeScriptProjectOptions, \"name\"> & {\n defaultReleaseBranch: string;\n } = {\n /**\n * This is a standard, so don't require it to passed in everywhere.\n */\n defaultReleaseBranch: \"main\",\n\n /**\n * Enable reset task by default.\n */\n resetTask: true,\n\n /**\n * Packaging options\n */\n packageManager: NodePackageManager.PNPM,\n pnpmVersion: pnpmVersion,\n licensed: userOptions.license !== undefined || false,\n copyrightOwner: \"CodeDrifters\",\n release: false,\n\n /**\n * Don't add sample code.\n */\n sampleCode: false,\n\n ...(useJest\n ? {\n /**\n * Make sure jest config is stored outside of package.json\n */\n jestOptions: {\n configFilePath: \"jest.config.json\",\n jestConfig: {\n roots: [`<rootDir>/src`],\n transform: {\n [\"^.+\\\\.[t]sx?$\"]: new Transform(\"@swc/jest\"),\n },\n moduleFileExtensions: [\"js\", \"ts\"],\n },\n },\n /**\n * SWC for faster testing\n */\n devDeps: [\"@swc/jest\", \"@swc/core\"] as string[],\n }\n : {\n jest: false,\n devDeps: [] as string[],\n }),\n\n /**\n * Turn on prettier formatting\n */\n prettier: true,\n\n /**\n * Don't package test files.\n */\n npmIgnoreOptions: {\n ignorePatterns: [\"*.spec.*\", \"*.test.*\"],\n },\n\n /**\n * Options for the automated dependency upgrade task / workflow\n * Automatically exclude any packages that are managed by the root\n * project as default catalog dependencies since we want to let the\n * catalog manage those dependencies.\n */\n depsUpgrade: true,\n depsUpgradeOptions: {\n workflow: false,\n exclude: Object.keys(pnpmWorkspace?.defaultCatalog || {}),\n ...(userOptions.parent && userOptions.parent instanceof MonorepoProject\n ? {\n workflowOptions: {\n schedule: UpgradeDependenciesSchedule.WEEKLY,\n },\n cooldown: 1,\n }\n : {}),\n },\n\n /**\n * Only release when the package folder source content or package.json\n * (version, dependencies) changes.\n */\n releaseTrigger: ReleaseTrigger.continuous({\n paths: [\n `${userOptions.outdir}/src/**`,\n `${userOptions.outdir}/package.json`,\n ],\n }),\n };\n\n /*************************************************************************\n *\n * Merge defaults into user options\n *\n ************************************************************************/\n\n const options: TypeScriptProjectOptions &\n typescript.TypeScriptProjectOptions = merge(defaultOptions, userOptions);\n\n super(options);\n\n /**\n * Use catalog version for @types/node so all packages share a single\n * pinned version (overrides projen's default @types/node@*).\n */\n this.addDevDeps(\"@types/node@catalog:\");\n\n /**\n * Exclude test files from the main tsconfig only (not tsconfig.dev) so\n * tsc --build compiles only library code (avoids pulling in test-runner\n * types e.g. Vitest/Vite). ESLint and tests still use tsconfig.dev which\n * includes test files.\n */\n this.tsconfig?.addExclude(\"**/*.test.*\");\n this.tsconfig?.addExclude(\"**/*.spec.*\");\n\n /**\n * When using Jest, remove ts-jest since we use @swc/jest.\n * When using Vitest, add the Vitest component (test task + config + deps).\n */\n if (options.testRunner === TestRunner.VITEST) {\n new Vitest(this, {\n config: {\n include: [\"src/**/*.{test,spec}.?(c|m)[jt]s?(x)\"],\n ...options.vitestOptions?.config,\n },\n ...options.vitestOptions,\n });\n } else {\n this.deps.removeDependency(\"ts-jest\");\n }\n\n /**\n * Specify package manager\n */\n this.package.file.addOverride(\n \"packageManager\",\n `pnpm@${options.pnpmVersion}`,\n );\n\n /**\n *\n * Disable this rule for all test files.\n *\n * Unless we turn this off, ESLint will suggest that anything found in a test\n * needs to be a dep instead of a devDep. Projen actually already turns off\n * the rule for files in the tests/* folder but since we commonly put tests\n * next to the code it's testing, we need to do this ourselves.\n *\n */\n this.eslint?.addOverride({\n files: [\"**/*.test.*\", \"**/*.spec.*\"],\n rules: {\n \"import/no-extraneous-dependencies\": \"off\",\n },\n });\n\n /**\n * Some standard ignores for all projects.\n */\n this.gitignore?.addPatterns(\".DS_Store\", \"test-reports\");\n this.npmignore?.addPatterns(\"*.spec.*\", \"*.test.*\", \"__fixtures__\");\n\n /**\n * If turbo is active in the parent project, configure it here.\n */\n const turboActive =\n userOptions.parent && TurboRepo.of(userOptions.parent) !== undefined;\n if (turboActive) {\n const turbo = new TurboRepo(this);\n turbo.compileTask?.outputs.push(\"dist/**\");\n turbo.compileTask?.outputs.push(\"lib/**\");\n //turbo.testTask?.inputs.push(\"src/**\");\n }\n\n /**\n * AI agent configuration — opt-in per project. Does not propagate from\n * parent MonorepoProject, so sub-projects don't render duplicate\n * `.cursor/` / `.claude/` / `CLAUDE.md` files into their own outdir.\n */\n if (\n options.agentConfig === true ||\n typeof options.agentConfig === \"object\"\n ) {\n new AgentConfig(\n this,\n typeof options.agentConfig === \"object\" ? options.agentConfig : {},\n );\n }\n\n /**\n * Add reset task if enabled.\n */\n if (options.resetTask !== false) {\n const defaultResetTaskOptions: ResetTaskOptions = {\n pathsToRemove: [\n \"node_modules\",\n \"dist\",\n \"lib\",\n \"coverage\",\n \"test-reports\",\n \".turbo\",\n \"tsconfig.tsbuildinfo\",\n this.artifactsDirectory,\n ],\n };\n const userResetTaskOptions = options.resetTaskOptions ?? {};\n const resetTaskOptions: ResetTaskOptions = merge(\n defaultResetTaskOptions,\n {\n ...userResetTaskOptions,\n pathsToRemove: [\n ...(defaultResetTaskOptions.pathsToRemove ?? []),\n ...(userResetTaskOptions.pathsToRemove ?? []),\n ],\n },\n );\n new ResetTask(this, resetTaskOptions);\n }\n\n /**\n *\n */\n\n if (options.parent && options.parent instanceof MonorepoProject) {\n // Install dependencies via the parent project\n /* @ts-ignore access private method */\n const originalResolve = this.package.resolveDepsAndWritePackageJson;\n /* @ts-ignore access private method */\n this.package.installDependencies = () => {\n (options.parent as MonorepoProject).requestInstallDependencies({\n resolveDepsAndWritePackageJson: () =>\n originalResolve.apply(this.package),\n });\n };\n /* @ts-ignore access private method */\n this.package.resolveDepsAndWritePackageJson = () => {};\n }\n }\n}\n","import { BuildWorkflowOptions } from \"projen/lib/build\";\nimport { WorkflowSteps } from \"projen/lib/github\";\nimport {\n NodePackageManager,\n UpgradeDependenciesSchedule,\n} from \"projen/lib/javascript\";\nimport {\n TypeScriptAppProject,\n TypeScriptProjectOptions,\n} from \"projen/lib/typescript\";\nimport { merge } from \"ts-deepmerge\";\nimport { ProjectMetadata } from \"./project-metadata\";\nimport { ProjectMetadataOptions } from \"./project-metadata-options\";\nimport { AgentConfig } from \"../agent/agent-config\";\nimport { AgentConfigOptions } from \"../agent/agent-config-options\";\nimport { PnpmWorkspace, PnpmWorkspaceOptions } from \"../pnpm/pnpm-workspace\";\nimport { ResetTask, ResetTaskOptions } from \"../tasks/reset-task\";\nimport {\n ROOT_CI_TASK_NAME,\n TurboRepo,\n TurboRepoOptions,\n} from \"../turbo/turbo-repo\";\nimport { VERSION } from \"../versions\";\nimport { VSCodeConfig } from \"../vscode/vscode\";\nimport {\n addApproveMergeUpgradeWorkflow,\n type ApproveMergeUpgradeOptions,\n} from \"../workflows/approve-merge-upgrade\";\nimport { addBuildCompleteJob } from \"../workflows/build-complete-job\";\nimport {\n addSyncLabelsWorkflow,\n type SyncLabelsOptions,\n} from \"../workflows/sync-labels\";\n\nconst CONFIGULATOR_PACKAGE_NAME = \"@codedrifters/configulator\";\n\n/*******************************************************************************\n *\n * Monorepo Root Project.\n *\n * This project should be used as the base project for other projects in a\n * monorepo. The Monorepo root project generally won't contain any code, but it\n * will contain configuration for the monorepo, such as package management,\n * linting, testing, and other project-wide settings.\n *\n ******************************************************************************/\n\nexport interface IDependencyResolver {\n resolveDepsAndWritePackageJson(): boolean;\n}\n\n/**\n * Configuration options for the monorepo.\n */\nexport interface MonorepoProjectOptions extends Omit<\n TypeScriptProjectOptions,\n \"defaultReleaseBranch\"\n> {\n /**\n * Turn on Turborepo support.\n *\n * @default true\n */\n turbo?: boolean;\n\n /**\n * Optionsal options for turborepo config\n */\n turboOptions?: TurboRepoOptions;\n\n /**\n * Enable the reset task that deletes all build artifacts.\n *\n * @default true\n */\n resetTask?: boolean;\n\n /**\n * Options for the reset task.\n */\n resetTaskOptions?: ResetTaskOptions;\n\n /**\n * PNPM options for the monorepo.\n */\n pnpmOptions?: {\n /**\n * The version of PNPM to use in the monorepo.\n * @default VERSION.PNPM_VERSION\n * @see {@link src/versions.ts}\n */\n version?: string;\n\n /**\n * Optional pnpm options for the monorepo workspace file.\n */\n pnpmWorkspaceOptions?: PnpmWorkspaceOptions;\n };\n\n /**\n * When set, adds the approve-and-merge-upgrade workflow (ADR 0001 §2).\n * Uses a second GitHub App to approve and merge the dependency-upgrade PR\n * when it has the auto-approve label and head branch matches. Trigger types\n * exclude `opened` to prevent double approval.\n *\n * @see ApproveMergeUpgradeOptions\n */\n readonly approveMergeUpgradeOptions?: ApproveMergeUpgradeOptions;\n\n /**\n * Whether this monorepo consumes @codedrifters/configulator from a registry (npm).\n * When true, the upgrade workflow adds steps to sync configulator and synthesize.\n * Set to false when configulator is developed in this repo (e.g. workspace dependency).\n *\n * @default true\n */\n readonly configulatorRegistryConsumer?: boolean;\n\n /**\n * Project metadata configuration. Provides repository identity,\n * GitHub project context, and organizational details consumed by\n * AgentConfig and other features at synthesis time.\n *\n * - `undefined` or `{}`: auto-instantiate with auto-detection (default)\n * - `ProjectMetadataOptions`: explicit metadata configuration\n * - `false`: disable ProjectMetadata entirely\n *\n * @default {} (auto-detect from package.json)\n */\n readonly projectMetadata?: ProjectMetadataOptions | false;\n\n /**\n * AI agent configuration (Cursor, Claude Code rules).\n * Generates rule files at the monorepo root with auto-detected bundles\n * based on project and subproject introspection.\n *\n * - `true` or `{}`: enable with auto-detected defaults\n * - `AgentConfigOptions`: enable with explicit configuration\n * - `false` or `undefined`: disabled (default)\n *\n * @default false\n */\n readonly agentConfig?: AgentConfigOptions | boolean;\n\n /**\n * Sync GitHub labels from a config file using EndBug/label-sync.\n * Generates `.github/labels.yml` and a sync workflow.\n *\n * - `true` or `undefined`: enable with default priority labels (default)\n * - `SyncLabelsOptions`: enable with custom label configuration\n * - `false`: disable label syncing\n *\n * @default true\n */\n readonly syncLabels?: SyncLabelsOptions | boolean;\n}\n\ninterface AppliedOptions\n extends TypeScriptProjectOptions, MonorepoProjectOptions {}\n\n/**\n * Per-instance list of post-install dependency resolvers. Stored in a WeakMap\n * so MonorepoProject has no private instance property and its type remains\n * structural across package versions (avoids TS2322 when two configulator\n * versions are in the dependency tree).\n */\nconst postInstallDependenciesMap = new WeakMap<\n MonorepoProject,\n Array<() => boolean>\n>();\n\nexport class MonorepoProject extends TypeScriptAppProject {\n /**\n * Version of PNPM which the whole monorepo should use.\n */\n readonly pnpmVersion: string;\n\n /**\n * Whether this monorepo consumes configulator from a registry (drives upgrade workflow steps).\n */\n readonly configulatorRegistryConsumer: boolean;\n\n constructor(userOptions: MonorepoProjectOptions) {\n /***************************************************************************\n *\n * BUILD WORKFLOW OPTIONS\n *\n * discover some turbo options for build workflow, if needed.\n *\n **************************************************************************/\n\n const buildWorkflowOptions: Partial<BuildWorkflowOptions> = userOptions\n .turboOptions?.remoteCacheOptions\n ? TurboRepo.buildWorkflowOptions(\n userOptions.turboOptions.remoteCacheOptions,\n )\n : {};\n\n /***************************************************************************\n *\n * DEFAULT OPTIONS\n *\n * These are the default options unless you override with option inputs.\n *\n **************************************************************************/\n\n const defaultOptions: Omit<\n MonorepoProjectOptions,\n \"name\" | \"defaultReleaseBranch\"\n > = {\n /**\n * Use typescript based config file.\n */\n projenrcTs: true,\n\n /**\n * Projen version should be pinned to the local specified version.\n */\n projenVersion: \"catalog:\",\n\n /**\n * Use Prettier for code formatting.\n */\n prettier: true,\n\n /**\n * Not licensed by default.\n */\n licensed: false,\n\n /**\n * GitHub options for the monorepo.\n * Don't enable mergify by default.\n */\n githubOptions: {\n mergify: false,\n\n /**\n * Configure pull request linting to validate PR titles follow Conventional Commits.\n * By default, all conventional commit types are allowed, providing flexibility\n * for different types of changes (features, fixes, documentation, refactoring, etc.).\n */\n pullRequestLintOptions: {\n semanticTitleOptions: {\n /**\n * Allowed conventional commit types for PR titles.\n * This includes all standard types from the Conventional Commits specification:\n * - feat: New features\n * - fix: Bug fixes\n * - docs: Documentation changes\n * - style: Code style changes (formatting, etc.)\n * - refactor: Code refactoring\n * - perf: Performance improvements\n * - test: Test additions or changes\n * - build: Build system changes\n * - ci: CI configuration changes\n * - chore: Maintenance tasks\n * - revert: Revert commits\n */\n types: [\n \"feat\",\n \"fix\",\n \"docs\",\n \"style\",\n \"refactor\",\n \"perf\",\n \"test\",\n \"build\",\n \"ci\",\n \"chore\",\n \"revert\",\n ],\n },\n },\n },\n\n /**\n * Default PNPM version to use in the monorepo.\n */\n pnpmVersion: VERSION.PNPM_VERSION,\n\n /**\n * By default treat as a registry consumer (upgrade workflow syncs configulator).\n */\n configulatorRegistryConsumer: true,\n\n /**\n * We don't want sample code generated for the root project.\n */\n sampleCode: false,\n\n /**\n * Jest is not required in the root project.\n */\n jest: false,\n\n /**\n * Don't release the root project.\n */\n release: false,\n\n /**\n * Uppgrade dependencies automatically unless otherwise instructed.\n * Exclude @codedrifters/configulator so the default upgrade task does not\n * upgrade it (version is often managed in-repo or via a separate sync step).\n */\n depsUpgrade: true,\n depsUpgradeOptions: {\n exclude: [\"@codedrifters/configulator\"],\n workflowOptions: {\n schedule: UpgradeDependenciesSchedule.DAILY,\n },\n cooldown: 1,\n },\n\n /**\n * Disable tsconfig.dev.json in the root since we aren't going to be\n * developing any code here. It's just a task runner and configuration\n * tool for sub-projects.\n */\n disableTsconfigDev: true,\n\n /**\n * Kill the srcdir in the root since we aren't using one. Projen's\n * default `tsconfig.include` still points at `src/**\\/*.ts`, so\n * callers that want to treat the monorepo root as a pure shell\n * should see an empty include — consumers add their own entries via\n * `tsconfig.addInclude(...)` (e.g. `.projenrc.ts`, `projenrc/**\\/*.ts`).\n */\n tsconfig: {\n compilerOptions: {\n rootDir: undefined,\n },\n exclude: [\"node_modules\"],\n },\n\n /**\n * Enable turborepo by default.\n */\n turbo: true,\n\n /**\n * Enable reset task by default.\n */\n resetTask: true,\n\n /**\n * Include self as a devDep\n */\n devDeps: [\"@codedrifters/configulator\"],\n\n /**\n * PNPM options for the monorepo.\n */\n pnpmOptions: {\n pnpmWorkspaceOptions: {\n defaultCatalog: {\n [\"@types/node\"]: VERSION.TYPES_NODE_VERSION,\n [\"aws-cdk\"]: VERSION.AWS_CDK_CLI_VERSION,\n [\"aws-cdk-lib\"]: VERSION.AWS_CDK_LIB_VERSION,\n [\"projen\"]: VERSION.PROJEN_VERSION,\n [\"constructs\"]: VERSION.AWS_CONSTRUCTS_VERSION,\n [\"turbo\"]: VERSION.TURBO_VERSION,\n },\n },\n },\n };\n\n /***************************************************************************\n *\n * REQUIRED OPTIONS\n *\n * These options cannot be changed by the user.\n *\n **************************************************************************/\n\n const requiredOptions: Omit<TypeScriptProjectOptions, \"name\"> = {\n /**\n * This is required because it's standard practice and also to simplify\n * some workflow design.\n */\n defaultReleaseBranch: \"main\",\n\n /**\n * Use PNPM instead of the default (Yarn). Much of the ecosystem depends\n * on PNPM and making monorepos PNPM only simplifies many configurations.\n */\n packageManager: NodePackageManager.PNPM,\n\n /**\n * Some additional pre-build steps if we're using turbo's remote cache.\n * Set GIT_BRANCH_NAME so Turborepo remote cache hashes match between local and CI.\n */\n buildWorkflowOptions: {\n env: {\n GIT_BRANCH_NAME: \"${{ github.head_ref || github.ref_name }}\",\n ...buildWorkflowOptions?.env,\n ...userOptions.buildWorkflowOptions?.env,\n },\n permissions: {\n ...buildWorkflowOptions?.permissions,\n ...userOptions.buildWorkflowOptions?.permissions,\n },\n preBuildSteps: [\n ...(buildWorkflowOptions?.preBuildSteps ?? []),\n ...(userOptions.buildWorkflowOptions?.preBuildSteps ?? []),\n ],\n },\n };\n\n /***************************************************************************\n *\n * CONSTRUCTOR\n *\n * Combines default options with user provided options and required options.\n * Store the options in a const so we can use them after super(), farther\n * into the constructor for additional configuration.\n *\n **************************************************************************/\n\n const options: AppliedOptions = merge(\n defaultOptions,\n userOptions,\n requiredOptions,\n );\n\n super({ ...options });\n\n postInstallDependenciesMap.set(this, []);\n\n /**\n * Projen's TypeScriptProject seeds `tsconfig.include` with\n * `<srcdir>/**\\/*.ts` by default. MonorepoProject is a shell with no\n * srcdir, so drop that entry — consumers add their own includes (e.g.\n * `.projenrc.ts`, `projenrc/**\\/*.ts`) via `this.tsconfig?.addInclude`.\n */\n this.tsconfig?.removeInclude(`${this.srcdir}/**/*.ts`);\n\n /***************************************************************************\n *\n * PUBLIC PROPS\n *\n * Some props are hidden by Projen and we need to expose them for the\n * monorepo to work properly. This is where we store them.\n *\n **************************************************************************/\n\n this.pnpmVersion = options.pnpmVersion!;\n this.configulatorRegistryConsumer =\n options.configulatorRegistryConsumer ?? true;\n\n /***************************************************************************\n *\n * CUSTOM CONFIGS\n *\n * We add some additional configurations to the monorepo root project below\n * such as Turborepo, VS Code config, and the PNPM workspace file.\n *\n **************************************************************************/\n\n /**\n * Add VSCode configuration\n */\n new VSCodeConfig(this);\n\n /**\n * Add workspace definition to PNPM root\n */\n new PnpmWorkspace(this, options.pnpmOptions?.pnpmWorkspaceOptions);\n\n /**\n * Turn on turborepo support if requested.\n */\n if (options.turbo) {\n new TurboRepo(this, options.turboOptions);\n\n this.buildWorkflow?.addPostBuildSteps(\n {\n name: \"Build Sub Projects\",\n run: `npx projen ${ROOT_CI_TASK_NAME}`,\n },\n WorkflowSteps.uploadArtifact({\n name: \"Upload Turbo runs\",\n if: \"always()\",\n continueOnError: true,\n with: {\n name: \"turbo-runs\",\n path: \".turbo/runs\",\n },\n }),\n );\n }\n\n /**\n * Add reset task if enabled.\n */\n if (options.resetTask !== false) {\n const defaultResetTaskOptions: ResetTaskOptions = {\n pathsToRemove: [\"node_modules\", \".turbo\", \"dist\", \"lib\"],\n };\n const userResetTaskOptions = options.resetTaskOptions ?? {};\n const resetTaskOptions: ResetTaskOptions = merge(\n defaultResetTaskOptions,\n {\n ...userResetTaskOptions,\n pathsToRemove: [\n ...(defaultResetTaskOptions.pathsToRemove ?? []),\n ...(userResetTaskOptions.pathsToRemove ?? []),\n ],\n },\n );\n new ResetTask(this, resetTaskOptions);\n }\n\n /**\n * Specify package manager\n */\n // const pnpmVersion = options.pnpmVersion ?? VERSION.PNPM_VERSION;\n this.package.file.addOverride(\n \"packageManager\",\n `pnpm@${options.pnpmVersion}`,\n );\n\n /**\n * Add some silly things to the gitignore.\n */\n this.gitignore?.addPatterns(\".DS_Store\", \"test-reports\");\n\n /**\n * Use catalog versions for constructs and @types/node\n */\n this.addDevDeps(\"constructs@catalog:\", \"@types/node@catalog:\");\n\n if (options.approveMergeUpgradeOptions) {\n addApproveMergeUpgradeWorkflow(this, options.approveMergeUpgradeOptions);\n }\n\n /**\n * Project metadata — auto-instantiated unless explicitly disabled.\n */\n if (options.projectMetadata !== false) {\n new ProjectMetadata(\n this,\n typeof options.projectMetadata === \"object\"\n ? options.projectMetadata\n : {},\n );\n }\n\n /**\n * Enable AI agent configuration if requested.\n */\n if (options.agentConfig) {\n new AgentConfig(\n this,\n typeof options.agentConfig === \"object\" ? options.agentConfig : {},\n );\n }\n\n /**\n * Sync GitHub labels if enabled. When AgentConfig is present, its\n * active bundles contribute labels to `.github/labels.yml` so a\n * bundle can ship the labels its rules depend on.\n */\n if (options.syncLabels !== false) {\n const syncLabelsOptions =\n typeof options.syncLabels === \"object\" ? options.syncLabels : {};\n const agentConfig = AgentConfig.of(this);\n addSyncLabelsWorkflow(this, {\n ...syncLabelsOptions,\n bundles: syncLabelsOptions.bundles ?? agentConfig?.activeBundles,\n });\n }\n\n /**\n * Append the \"complete\" gate job to the build workflow (ADR 0004). Requires\n * build to succeed and all other jobs to succeed or be skipped.\n */\n if (this.buildWorkflow) {\n addBuildCompleteJob(this.buildWorkflow);\n }\n\n // Mutate the upgrade workflow job: add subproject upgrade step (always), and\n // for consumers add sync + synthesize before it. addPostBuildSteps runs too\n // late because the workflow is created in UpgradeDependencies constructor.\n const upgradeWorkflow = this.github?.tryFindWorkflow(\"upgrade\");\n const upgradeJob = upgradeWorkflow?.getJob(\"upgrade\");\n const jobWithSteps =\n upgradeJob && \"steps\" in upgradeJob ? upgradeJob : undefined;\n if (jobWithSteps?.steps && Array.isArray(jobWithSteps.steps)) {\n const insertIndex = 4; // after checkout, setup, install, upgrade\n if (this.configulatorRegistryConsumer) {\n jobWithSteps.steps.splice(insertIndex, 0, {\n name: `Sync ${CONFIGULATOR_PACKAGE_NAME} in workspace`,\n run: `pnpm update -r ${CONFIGULATOR_PACKAGE_NAME}`,\n });\n jobWithSteps.steps.splice(insertIndex + 1, 0, {\n name: \"Synthesize\",\n run: this.runTaskCommand(this.defaultTask!),\n });\n }\n jobWithSteps.steps.splice(\n insertIndex + (this.configulatorRegistryConsumer ? 2 : 0),\n 0,\n {\n name: \"Run subproject upgrades\",\n run: \"pnpm -r run upgrade\",\n },\n );\n }\n }\n\n /**\n * Allows a sub project to request installation of dependency at the Monorepo root\n * They must provide a function that is executed after dependencies have been installed\n * If this function returns true, the install command is run for a second time after all sub project requests have run.\n * This is used to resolve dependency versions from `*` to a concrete version constraint.\n */\n public requestInstallDependencies(resolver: IDependencyResolver) {\n postInstallDependenciesMap\n .get(this)!\n .push(resolver.resolveDepsAndWritePackageJson);\n }\n\n /**\n * Hooks into the install dependencies cycle\n */\n public postSynthesize() {\n const postInstallDependencies = postInstallDependenciesMap.get(this);\n if (postInstallDependencies?.length) {\n const nodePkg: any = this.package;\n nodePkg.installDependencies();\n\n const completedRequests = postInstallDependencies.map((request) =>\n request(),\n );\n if (completedRequests.some(Boolean)) {\n nodePkg.installDependencies();\n }\n\n postInstallDependenciesMap.set(this, []);\n }\n }\n}\n","import { Component, Project } from \"projen\";\nimport { TypeScriptProject } from \"../projects/typescript-project\";\nimport { TurboRepo } from \"../turbo/turbo-repo\";\nimport { TurboRepoTask } from \"../turbo/turbo-repo-task\";\n\n/*******************************************************************************\n *\n * Reset Task Component\n *\n * Adds a \"reset\" task that deletes all build artifacts produced by the build\n * process. This includes node_modules, lib, dist, coverage, test-reports,\n * .turbo, and tsconfig.tsbuildinfo.\n *\n ******************************************************************************/\n\nexport interface ResetTaskOptions {\n /**\n * Custom output directory to delete (overrides tsconfig artifactsDirectory detection).\n *\n * @default - detected from typescript project.artifactsDirectory or \"lib\"\n */\n readonly artifactsDirectory?: string;\n\n /**\n * Array of glob patterns for paths to remove.\n * If empty, the artifactsDirectory will be added automatically.\n *\n * @default []\n */\n readonly pathsToRemove?: string[];\n\n /**\n * Name of the task to create.\n *\n * @default \"reset\"\n */\n readonly taskName?: string;\n}\n\nexport class ResetTask extends Component {\n /**\n * Static method to discover reset task in a project.\n */\n public static of(project: Project): ResetTask | undefined {\n const isDefined = (c: Component): c is ResetTask => c instanceof ResetTask;\n return project.components.find(isDefined);\n }\n\n /**\n * The output directory to delete (from tsconfig or custom).\n */\n public readonly artifactsDirectory: string;\n\n /**\n * The final array of paths that will be removed by the reset task.\n */\n public readonly pathsToRemove: string[];\n\n /**\n * The name of the task that was created.\n */\n public readonly taskName: string;\n\n constructor(\n public readonly project: Project,\n options: ResetTaskOptions = {},\n ) {\n super(project);\n\n /**\n * Determine the output directory.\n * 1. Use custom artifactsDirectory if provided\n * 2. Use the artifacts directory if project is TypeScriptProject\n * 3. Default to \"lib\"\n */\n this.artifactsDirectory = options.artifactsDirectory\n ? options.artifactsDirectory\n : project instanceof TypeScriptProject\n ? project.artifactsDirectory\n : \"lib\";\n\n /**\n * Build the paths array to remove.\n * If pathsToRemove is empty, add artifactsDirectory.\n * If pathsToRemove is not empty, use it as-is (artifactsDirectory is not automatically added).\n * Remove duplicate entries from the array.\n */\n const pathsToRemove = options.pathsToRemove ?? [];\n const finalPaths =\n pathsToRemove.length === 0 ? [this.artifactsDirectory] : pathsToRemove;\n\n /**\n * Remove duplicate paths from the array.\n */\n this.pathsToRemove = Array.from(new Set(finalPaths));\n\n /**\n * Determine the task name.\n */\n this.taskName = options.taskName ?? \"reset\";\n\n /**\n * Create the reset task.\n */\n const resetTask = this.project.tasks.addTask(this.taskName, {\n description:\n \"Delete build artifacts specified by pathsToRemove option, or artifactsDirectory if pathsToRemove is empty\",\n });\n\n /**\n * Delete build artifacts with existence checks.\n * Using shell conditionals to only delete if paths exist.\n * Using -e to check existence (works for both files and directories).\n */\n this.pathsToRemove.forEach((path) => {\n resetTask.exec(`[ -e \"${path}\" ] && rm -rf ${path} || true`);\n });\n\n /**\n * Turbo tasks are added after all components are created.\n * This assumes turbo is built first so that it's available to be\n * referenced. This could introduce problems in future but works for now.\n */\n\n /**\n * Check if turborepo is active.\n */\n const rootHasTurbo = TurboRepo.of(this.project.root) !== undefined;\n const isSubproject = this.project !== this.project.root;\n const isRootProject = this.project === this.project.root;\n\n /**\n * If turborepo is active for the subproject, add turbo tasks.\n */\n if (isSubproject && rootHasTurbo) {\n /**\n * Get TurboRepo instance for this subproject.\n * It should exist by now since preSynthesize runs after all components are created.\n */\n const turbo = TurboRepo.of(this.project);\n if (turbo && !turbo.isRootProject) {\n /**\n * Create turbo:reset task (or turbo:${taskName}).\n */\n const turboResetTask = new TurboRepoTask(this.project, {\n name: `turbo:${this.taskName}`,\n cache: false,\n });\n turbo.tasks.push(turboResetTask);\n\n /**\n * Create a turbo task with the same name as the reset task.\n */\n const turboTaskWithSameName = new TurboRepoTask(this.project, {\n name: this.taskName,\n cache: false,\n });\n turbo.tasks.push(turboTaskWithSameName);\n\n /**\n * turboResetTask depends on turboTaskWithSameName so that the reset task\n * can be run across all suprojects using turbo:reset as the entry point.\n */\n turboResetTask.dependsOn.push(turboTaskWithSameName.name);\n }\n }\n\n /**\n * If reset-task is in the root project, add a turbo task that will trigger\n * all the subtasks using dependsOn of \"^turbo:reset\".\n */\n if (isRootProject && rootHasTurbo) {\n const turbo = TurboRepo.of(this.project);\n if (turbo && turbo.isRootProject) {\n /**\n * Create turbo:reset task (or turbo:${taskName}) in the root project.\n * The ^ prefix means \"run this task in all dependencies first\".\n */\n const rootTurboResetTask = new TurboRepoTask(this.project, {\n name: `turbo:${this.taskName}`,\n dependsOn: [`^turbo:${this.taskName}`],\n cache: false,\n });\n turbo.tasks.push(rootTurboResetTask);\n\n /**\n * Create a turbo task with the same name as the reset task.\n */\n const turboTaskWithSameName = new TurboRepoTask(this.project, {\n name: this.taskName,\n cache: false,\n });\n turbo.tasks.push(turboTaskWithSameName);\n\n /**\n * rootTurboResetTask depends on turboTaskWithSameName so that the reset task\n * can be run across all suprojects using turbo:reset as the entry point.\n */\n rootTurboResetTask.dependsOn.push(turboTaskWithSameName.name);\n\n /**\n * Create reset:all task - a projen task that calls the turbo task.\n * This is similar to build:all in turbo-repo.ts.\n */\n const resetAllTask = this.project.tasks.addTask(\n `${this.taskName}:all`,\n {\n description: `Reset all build artifacts across the monorepo by running turbo:${this.taskName} in all subprojects.`,\n },\n );\n resetAllTask.exec(\"turbo telemetry disable\");\n resetAllTask.exec(\n `turbo turbo:${this.taskName} --summarize --concurrency=10`,\n );\n resetAllTask.exec(`pnpm ${this.taskName}`);\n }\n }\n }\n}\n","import { Component, vscode } from \"projen\";\nimport { TypeScriptAppProject } from \"projen/lib/typescript\";\n\n/*******************************************************************************\n *\n * Configure VSCode Settings\n *\n ******************************************************************************/\n\nexport class VSCodeConfig extends Component {\n constructor(project: TypeScriptAppProject) {\n super(project);\n\n /**\n * Create instance of config file.\n */\n const vsConfig = new vscode.VsCode(project);\n\n /**\n * Add some basic configuration settings to the VS Code settings file:\n *\n * - Set the tab size to 2 spaces\n * - Enable bracket pair colorization\n * - Highlight active bracket pairs\n * - Add rulers at 80 and 120 characters\n */\n const vsSettings = new vscode.VsCodeSettings(vsConfig);\n vsSettings.addSetting(\"editor.tabSize\", 2);\n vsSettings.addSetting(\"editor.detectIndentation\", false);\n vsSettings.addSetting(\"editor.bracketPairColorization.enabled\", true);\n vsSettings.addSetting(\"editor.guides.bracketPairs\", \"active\");\n vsSettings.addSetting(\"editor.rulers\", [80, 120]);\n\n /**\n * Add some ESLint specific settings to the VS Code settings file.\n */\n vsSettings.addSetting(\n \"editor.codeActionsOnSave\",\n { \"source.fixAll.eslint\": \"explicit\" },\n \"typescript\",\n );\n }\n}\n","import { JobPermission } from \"projen/lib/github/workflows-model\";\nimport type { NodeProject } from \"projen/lib/javascript\";\n\n/** Merge methods supported by enable-pull-request-automerge. */\nexport const MERGE_METHODS = {\n SQUASH: \"squash\",\n MERGE: \"merge\",\n REBASE: \"rebase\",\n} as const;\n\n/** Merge method for the approve-and-merge-upgrade workflow. */\nexport type MergeMethod = (typeof MERGE_METHODS)[keyof typeof MERGE_METHODS];\n\n/**\n * Options for the approve-and-merge-upgrade workflow (ADR 0001 §2).\n * When set, adds a workflow that approves and merges the dependency-upgrade PR\n * when it has the auto-approve label and head branch matches. Trigger types\n * exclude `opened` to prevent double approval when the PR is created with the label.\n */\nexport interface ApproveMergeUpgradeOptions {\n /**\n * Workflow file name (display name in Actions tab).\n * @default \"approve-and-merge-upgrade\"\n */\n readonly workflowName?: string;\n\n /**\n * Label that must be present on the PR to trigger approve-and-merge.\n * @default \"auto-approve\"\n */\n readonly autoApproveLabel?: string;\n\n /**\n * Head branch name the PR must target (e.g. the branch created by the upgrade workflow).\n * @default \"github-actions/upgrade\"\n */\n readonly headBranch?: string;\n\n /**\n * GitHub usernames allowed as PR authors (e.g. automation bot logins).\n * The workflow runs only when the PR user is in this list.\n */\n readonly allowedUsernames: string[];\n\n /**\n * Repository secret name for the approval GitHub App ID.\n * @default \"APPROVAL_APP_ID\"\n */\n readonly approvalAppIdSecret?: string;\n\n /**\n * Repository secret name for the approval GitHub App private key (PEM).\n * @default \"APPROVAL_APP_PRIVATE_KEY\"\n */\n readonly approvalAppPrivateKeySecret?: string;\n\n /**\n * Merge method for enable-pull-request-automerge.\n * @default \"squash\"\n */\n readonly mergeMethod?: MergeMethod;\n\n /**\n * Optional branch filters for pull_request_target (e.g. base branches).\n * @see https://docs.github.com/en/actions/using-workflows/events-that-trigger-workflows#pull_request_target\n */\n readonly branches?: string[];\n}\n\nconst DEFAULT_WORKFLOW_NAME = \"approve-and-merge-upgrade\";\nconst DEFAULT_AUTO_APPROVE_LABEL = \"auto-approve\";\nconst DEFAULT_HEAD_BRANCH = \"github-actions/upgrade\";\nconst DEFAULT_APPROVAL_APP_ID_SECRET = \"APPROVAL_APP_ID\";\nconst DEFAULT_APPROVAL_APP_PRIVATE_KEY_SECRET = \"APPROVAL_APP_PRIVATE_KEY\";\nconst DEFAULT_MERGE_METHOD = MERGE_METHODS.SQUASH;\n\n/**\n * Trigger types for pull_request_target. Excludes `opened` so that when the\n * upgrade workflow creates a PR with the auto-approve label, GitHub emits both\n * `opened` and `labeled` and we avoid running the workflow twice (double approval).\n */\nconst PULL_REQUEST_TARGET_TYPES = [\n \"labeled\",\n \"synchronize\",\n \"reopened\",\n \"ready_for_review\",\n] as const;\n\n/**\n * Adds the approve-and-merge-upgrade workflow to the project.\n * Uses a GitHub App token for approve + enable automerge (squash by default).\n *\n * @param project - A NodeProject with GitHub (e.g. MonorepoProject)\n * @param options - Options for the workflow; allowedUsernames is required\n */\nexport function addApproveMergeUpgradeWorkflow(\n project: NodeProject,\n options: ApproveMergeUpgradeOptions,\n): void {\n const workflowName = options.workflowName ?? DEFAULT_WORKFLOW_NAME;\n const autoApproveLabel =\n options.autoApproveLabel ?? DEFAULT_AUTO_APPROVE_LABEL;\n const headBranch = options.headBranch ?? DEFAULT_HEAD_BRANCH;\n const allowedUsernames = options.allowedUsernames;\n const appIdSecret =\n options.approvalAppIdSecret ?? DEFAULT_APPROVAL_APP_ID_SECRET;\n const privateKeySecret =\n options.approvalAppPrivateKeySecret ??\n DEFAULT_APPROVAL_APP_PRIVATE_KEY_SECRET;\n const mergeMethod = options.mergeMethod ?? DEFAULT_MERGE_METHOD;\n\n const workflow = project.github?.addWorkflow(workflowName);\n if (!workflow) return;\n\n workflow.on({\n pullRequestTarget: {\n types: [...PULL_REQUEST_TARGET_TYPES],\n ...(options.branches && options.branches.length > 0\n ? { branches: options.branches }\n : {}),\n },\n });\n\n const jobCondition = [\n `contains(github.event.pull_request.labels.*.name, '${autoApproveLabel}')`,\n `github.event.pull_request.head.ref == '${headBranch}'`,\n `(${allowedUsernames.map((u) => `github.event.pull_request.user.login == '${u}'`).join(\" || \")})`,\n ].join(\" && \");\n\n workflow.addJobs({\n \"approve-and-merge\": {\n name: \"Approve and merge upgrade PR\",\n runsOn: [\"ubuntu-latest\"],\n permissions: {\n pullRequests: JobPermission.WRITE,\n contents: JobPermission.WRITE,\n },\n if: jobCondition,\n steps: [\n {\n name: \"Generate token\",\n id: \"generate_token\",\n uses: \"actions/create-github-app-token@v2\",\n with: {\n \"app-id\": `\\${{ secrets.${appIdSecret} }}`,\n \"private-key\": `\\${{ secrets.${privateKeySecret} }}`,\n },\n },\n {\n name: \"Auto-approve\",\n uses: \"hmarr/auto-approve-action@f0939ea97e9205ef24d872e76833fa908a770363\",\n with: {\n \"github-token\": \"${{ steps.generate_token.outputs.token }}\",\n },\n },\n {\n name: \"Enable auto-merge (squash)\",\n uses: \"peter-evans/enable-pull-request-automerge@v3\",\n with: {\n token: \"${{ steps.generate_token.outputs.token }}\",\n \"pull-request-number\": \"${{ github.event.pull_request.number }}\",\n \"merge-method\": mergeMethod,\n },\n },\n ],\n },\n });\n}\n","import { BuildWorkflow } from \"projen/lib/build\";\nimport { JobPermission } from \"projen/lib/github/workflows-model\";\n\n/** Job ID of the main build job (Projen constant). */\nconst BUILD_JOB_ID = \"build\";\n\n/** Name of the gate job appended to build workflows (ADR 0004). */\nexport const COMPLETE_JOB_ID = \"complete\";\n\n/**\n * Projen's BuildWorkflow holds the underlying GithubWorkflow in a private\n * property. We use this shape to access it (cast via unknown).\n */\ninterface BuildWorkflowWithWorkflow {\n workflow: {\n jobs: Record<string, unknown>;\n addJob(id: string, job: Record<string, unknown>): void;\n };\n}\n\n/**\n * Builds the run script for the complete job step. Requires the build job to\n * succeed; all other jobs must succeed or be skipped (ADR 0004).\n * Uses \\$ so the output contains literal ${{ }} for GitHub Actions expressions.\n */\nfunction buildCompleteJobRunScript(jobIds: string[]): string {\n const lines: string[] = [];\n for (const id of jobIds) {\n const expr = \"${{ needs.\" + id + \".result }}\";\n if (id === BUILD_JOB_ID) {\n lines.push(\n `if [ \"${expr}\" != \"success\" ]; then echo \"Job ${id} must succeed\"; exit 1; fi`,\n );\n } else {\n lines.push(\n `if [ \"${expr}\" != \"success\" ] && [ \"${expr}\" != \"skipped\" ]; then echo \"Job ${id} must succeed or be skipped\"; exit 1; fi`,\n );\n }\n }\n return lines.join(\"\\n\");\n}\n\n/**\n * Appends the \"complete\" gate job to a build workflow (ADR 0004, issue #165).\n * The job runs after all other jobs, uses {@code if: always()}, and succeeds\n * only when the build job succeeded and every other job succeeded or was skipped.\n * Call this for the default build workflow and for any build workflow created\n * by Configulator (e.g. AwsDeployWorkflow).\n *\n * @param buildWorkflow The Projen BuildWorkflow to append the complete job to.\n */\nexport function addBuildCompleteJob(buildWorkflow: BuildWorkflow): void {\n const w = (buildWorkflow as unknown as BuildWorkflowWithWorkflow).workflow;\n if (!w?.jobs || typeof w.addJob !== \"function\") {\n return;\n }\n const jobIds = Object.keys(w.jobs).filter((id) => id !== COMPLETE_JOB_ID);\n if (jobIds.length === 0) {\n return;\n }\n const runScript = buildCompleteJobRunScript(jobIds);\n w.addJob(COMPLETE_JOB_ID, {\n name: \"Complete\",\n needs: jobIds,\n if: \"always()\",\n runsOn: [\"ubuntu-latest\"],\n permissions: {\n contents: JobPermission.NONE,\n },\n steps: [\n {\n name: \"Verify all jobs succeeded or were skipped\",\n run: runScript,\n },\n ],\n });\n}\n","import { Component, Project, YamlFile } from \"projen\";\nimport { JobPermission } from \"projen/lib/github/workflows-model\";\nimport type { NodeProject } from \"projen/lib/javascript\";\nimport type { AgentRuleBundle } from \"../agent/agent-config-options\";\n\n/** A single GitHub label definition for EndBug/label-sync. */\nexport interface LabelDefinition {\n /** Label name (e.g. \"priority:high\"). */\n readonly name: string;\n\n /** Hex color without the leading `#` (e.g. \"B60205\"). */\n readonly color: string;\n\n /** Short description shown in the GitHub UI. */\n readonly description: string;\n}\n\n/** Options for the sync-labels workflow and labels config file. */\nexport interface SyncLabelsOptions {\n /**\n * Additional labels to sync alongside the standard defaults.\n * Merged with DEFAULT_STATUS_LABELS, DEFAULT_PRIORITY_LABELS, and\n * DEFAULT_TYPE_LABELS (standard labels are always included).\n */\n readonly labels?: ReadonlyArray<LabelDefinition>;\n\n /**\n * Remove labels from the repo that are not in the config file.\n * @default true\n */\n readonly deleteOtherLabels?: boolean;\n\n /**\n * Workflow file name (display name in the Actions tab).\n * @default \"sync-labels\"\n */\n readonly workflowName?: string;\n\n /**\n * Agent bundles whose contributed labels should be merged into\n * `.github/labels.yml`. Typically populated by the project type from\n * `AgentConfig.of(project)?.activeBundles` so bundle-supplied labels\n * only appear when the bundle is actually enabled.\n *\n * Merge order: Tier 1 defaults → bundle labels → user-supplied `labels`\n * (later entries override earlier ones on name collision).\n */\n readonly bundles?: ReadonlyArray<AgentRuleBundle>;\n}\n\n/** Default status labels. */\nexport const DEFAULT_STATUS_LABELS: ReadonlyArray<LabelDefinition> = [\n {\n name: \"status:ready\",\n color: \"0E8A16\",\n description: \"Task is ready for pickup\",\n },\n {\n name: \"status:in-progress\",\n color: \"FBCA04\",\n description: \"Actively being worked on\",\n },\n {\n name: \"status:ready-for-review\",\n color: \"1D76DB\",\n description: \"PR opened and awaiting review\",\n },\n {\n name: \"status:blocked\",\n color: \"D93F0B\",\n description: \"Blocked on a dependency or question\",\n },\n {\n name: \"status:done\",\n color: \"6F42C1\",\n description: \"Task completed and closed\",\n },\n {\n name: \"status:deferred\",\n color: \"C2E0C6\",\n description: \"Intentionally parked — not ready for pickup\",\n },\n {\n name: \"status:needs-attention\",\n color: \"FF0000\",\n description: \"Requires human review\",\n },\n];\n\n/** Default priority labels. */\nexport const DEFAULT_PRIORITY_LABELS: ReadonlyArray<LabelDefinition> = [\n {\n name: \"priority:critical\",\n color: \"B60205\",\n description: \"Critical priority — address immediately\",\n },\n {\n name: \"priority:high\",\n color: \"D93F0B\",\n description: \"High priority — pick before normal\",\n },\n {\n name: \"priority:medium\",\n color: \"E4E669\",\n description: \"Medium priority\",\n },\n {\n name: \"priority:low\",\n color: \"D4C5F9\",\n description: \"Low priority — skip if higher-priority work exists\",\n },\n {\n name: \"priority:trivial\",\n color: \"EDEDED\",\n description: \"Trivial priority — address when convenient\",\n },\n];\n\n/** Default type labels — one per conventional commit type. */\nexport const DEFAULT_TYPE_LABELS: ReadonlyArray<LabelDefinition> = [\n {\n name: \"type:feat\",\n color: \"1D76DB\",\n description: \"New feature or functionality\",\n },\n {\n name: \"type:fix\",\n color: \"D73A4A\",\n description: \"Bug fix\",\n },\n {\n name: \"type:docs\",\n color: \"0075CA\",\n description: \"Documentation only\",\n },\n {\n name: \"type:style\",\n color: \"BFD4F2\",\n description: \"Code style (formatting, whitespace) — no logic change\",\n },\n {\n name: \"type:refactor\",\n color: \"A2EEEF\",\n description: \"Code restructure — no feature or fix\",\n },\n {\n name: \"type:perf\",\n color: \"F9D0C4\",\n description: \"Performance improvement\",\n },\n {\n name: \"type:test\",\n color: \"BFD4F2\",\n description: \"Adding or updating tests\",\n },\n {\n name: \"type:build\",\n color: \"E6CCF5\",\n description: \"Build system or external dependencies\",\n },\n {\n name: \"type:ci\",\n color: \"D4C5F9\",\n description: \"CI configuration changes\",\n },\n {\n name: \"type:chore\",\n color: \"E6E6E6\",\n description: \"Maintenance tasks (deps, tooling, config)\",\n },\n {\n name: \"type:revert\",\n color: \"EDEDED\",\n description: \"Revert a previous commit\",\n },\n {\n name: \"type:release\",\n color: \"0E8A16\",\n description: \"Release preparation and version bumps\",\n },\n {\n name: \"type:hotfix\",\n color: \"B60205\",\n description: \"Urgent production fix\",\n },\n];\n\nconst DEFAULT_WORKFLOW_NAME = \"sync-labels\";\nconst LABELS_CONFIG_PATH = \".github/labels.yml\";\n\n/**\n * Adds a labels config file and a GitHub Actions workflow that syncs\n * labels to the repository using EndBug/label-sync.\n */\nexport function addSyncLabelsWorkflow(\n project: NodeProject,\n options: SyncLabelsOptions,\n): void {\n const workflowName = options.workflowName ?? DEFAULT_WORKFLOW_NAME;\n const deleteOtherLabels = options.deleteOtherLabels ?? true;\n\n // Merge order: Tier 1 defaults → bundle labels → user-supplied. Later\n // entries override earlier ones on name collision, so a consumer can\n // always override a bundle-contributed label without disabling the bundle.\n const labelMap = new Map<string, LabelDefinition>();\n for (const label of DEFAULT_STATUS_LABELS) {\n labelMap.set(label.name, label);\n }\n for (const label of DEFAULT_PRIORITY_LABELS) {\n labelMap.set(label.name, label);\n }\n for (const label of DEFAULT_TYPE_LABELS) {\n labelMap.set(label.name, label);\n }\n for (const bundle of options.bundles ?? []) {\n for (const label of bundle.labels ?? []) {\n labelMap.set(label.name, label);\n }\n }\n for (const label of options.labels ?? []) {\n labelMap.set(label.name, label);\n }\n const allLabels = [...labelMap.values()];\n\n // Generate .github/labels.yml\n new LabelsFile(project, allLabels);\n\n // Generate the sync workflow\n const workflow = project.github?.addWorkflow(workflowName);\n if (!workflow) {\n return;\n }\n\n workflow.on({\n push: {\n branches: [\"main\"],\n paths: [LABELS_CONFIG_PATH],\n },\n workflowDispatch: {},\n });\n\n workflow.addJobs({\n sync: {\n name: \"Sync labels\",\n runsOn: [\"ubuntu-latest\"],\n permissions: {\n contents: JobPermission.READ,\n issues: JobPermission.WRITE,\n },\n steps: [\n {\n name: \"Checkout\",\n uses: \"actions/checkout@v6\",\n },\n {\n name: \"Sync labels\",\n uses: \"EndBug/label-sync@v2\",\n with: {\n \"config-file\": LABELS_CONFIG_PATH,\n \"delete-other-labels\": deleteOtherLabels,\n token: \"${{ secrets.GITHUB_TOKEN }}\",\n },\n },\n ],\n },\n });\n}\n\n/**\n * Projen component that writes .github/labels.yml.\n * Separated so the YAML file participates in the normal synth lifecycle.\n */\nclass LabelsFile extends Component {\n constructor(project: Project, labels: ReadonlyArray<LabelDefinition>) {\n super(project);\n\n new YamlFile(project, LABELS_CONFIG_PATH, {\n obj: labels.map((l) => ({\n name: l.name,\n color: l.color,\n description: l.description,\n })),\n committed: true,\n });\n }\n}\n","import { awscdk } from \"projen\";\nimport { BuildWorkflow } from \"projen/lib/build\";\nimport {\n NodePackageManager,\n Transform,\n UpgradeDependenciesSchedule,\n} from \"projen/lib/javascript\";\nimport { ReleaseTrigger } from \"projen/lib/release\";\nimport { merge } from \"ts-deepmerge\";\nimport { MonorepoProject } from \"./monorepo-project\";\nimport { TestRunner } from \"./typescript-project\";\nimport { AgentConfig } from \"../agent/agent-config\";\nimport { AgentConfigOptions } from \"../agent/agent-config-options\";\nimport {\n AwsDeploymentConfig,\n AwsDeploymentTarget,\n AwsDeploymentTargetOptions,\n} from \"../aws\";\nimport { PnpmWorkspace } from \"../pnpm\";\nimport { ResetTask, ResetTaskOptions } from \"../tasks/reset-task\";\nimport { TurboRepo } from \"../turbo\";\nimport { VERSION } from \"../versions\";\nimport { Vitest, VitestOptions } from \"../vitest\";\nimport {\n AwsDeployWorkflow,\n DeployWorkflowOptions,\n} from \"../workflows/aws-deploy-workflow\";\nimport {\n AwsTeardownWorkflow,\n AwsTeardownWorkflowOptions,\n} from \"../workflows/aws-teardown-workflow\";\n\n/**\n * Configuration options for AwsCdkProject.\n *\n * AwsCdkProject must be parented to a `MonorepoProject` — the constructor\n * throws otherwise. Configulator assumes a single-package repo is still a\n * monorepo (with one workspace) so all conventions hold uniformly.\n */\nexport interface AwsCdkProjectOptions extends Omit<\n awscdk.AwsCdkTypeScriptAppOptions,\n \"defaultReleaseBranch\"\n> {\n /**\n * AWS deployment targets (dev / stage / prod accounts and regions). Each\n * entry creates an `AwsDeploymentTarget` component on the project.\n */\n readonly deploymentTargets?: Array<AwsDeploymentTargetOptions>;\n\n /**\n * AWS deploy workflows. If omitted, one workflow is auto-generated per\n * unique `awsStageType` present in `deploymentTargets`. Each auto-generated\n * workflow renders to its own `.github/workflows/*.yml` file.\n *\n * Pass an empty array (`[]`) to opt out of auto-derivation entirely without\n * supplying any workflows of your own — the array is truthy and short-circuits\n * the default. Useful when you intend to attach deploy jobs to an existing\n * build workflow yourself.\n */\n readonly deployWorkflows?: Array<DeployWorkflowOptions>;\n\n /**\n * Optional shared `BuildWorkflow` to attach all auto-derived deploy jobs to.\n * When set, every workflow generated from `deploymentTargets` re-uses this\n * build workflow instead of creating its own. Default behavior (omit) is one\n * separate yml file per stage type.\n *\n * Distinct from `buildWorkflow: boolean` inherited from\n * `AwsCdkTypeScriptAppOptions`, which toggles whether the projen-managed\n * build workflow is generated at all.\n */\n readonly sharedBuildWorkflow?: BuildWorkflow;\n\n /**\n * Test runner to use.\n *\n * @default TestRunner.JEST\n */\n readonly testRunner?: TestRunner;\n\n /**\n * Options for Vitest (only used when testRunner is 'vitest').\n */\n readonly vitestOptions?: VitestOptions;\n\n /**\n * Enable the reset task that deletes all build artifacts.\n *\n * @default true\n */\n readonly resetTask?: boolean;\n\n /**\n * Options for the reset task.\n */\n readonly resetTaskOptions?: ResetTaskOptions;\n\n /**\n * AI agent configuration (Cursor, Claude Code rules). Opt-in per project;\n * not inherited from the parent `MonorepoProject`.\n *\n * @default false\n */\n readonly agentConfig?: AgentConfigOptions | boolean;\n\n /**\n * Scheduled teardown workflow options. When provided, an `AwsTeardownWorkflow`\n * is attached to the parent `MonorepoProject` that periodically deletes\n * orphaned CloudFormation stacks whose branch no longer exists.\n */\n readonly teardownWorkflow?: AwsTeardownWorkflowOptions;\n}\n\n/**\n * AWS CDK TypeScript application with CodeDrifters conventions baked in.\n *\n * Always creates an `AwsDeploymentConfig` component (even with zero deployment\n * targets) so the `synth` task is consistently rewritten to emit into\n * `dist/<project-path>/cdk.out`. This is intentional and not opt-out: it\n * funnels every package's CDK output into one root-level `dist/` tree so\n * GitHub Actions workflows can pass artifacts between jobs uniformly.\n */\nexport class AwsCdkProject extends awscdk.AwsCdkTypeScriptApp {\n constructor(userOptions: AwsCdkProjectOptions) {\n /**\n * Configulator requires every project to live inside a MonorepoProject.\n * The catalog-based @types/node pin, the workspace install hook, and the\n * deploy workflow all assume the parent exists.\n */\n if (!(userOptions.parent instanceof MonorepoProject)) {\n throw new Error(\n \"AwsCdkProject must be parented to a MonorepoProject. Pass `parent: <MonorepoProject>` in the project options.\",\n );\n }\n\n const parent = userOptions.parent;\n const pnpmVersion = parent.pnpmVersion;\n const pnpmWorkspace = PnpmWorkspace.of(parent);\n\n /*************************************************************************\n *\n * Default Options\n *\n ************************************************************************/\n\n const testRunner = userOptions.testRunner ?? TestRunner.JEST;\n const useJest = testRunner === TestRunner.JEST;\n\n const defaultOptions: Omit<AwsCdkProjectOptions, \"name\"> & {\n defaultReleaseBranch: string;\n cdkVersion: string;\n } = {\n defaultReleaseBranch: \"main\",\n\n /**\n * Enable reset task by default.\n */\n resetTask: true,\n\n /**\n * Packaging options.\n */\n packageManager: NodePackageManager.PNPM,\n pnpmVersion: pnpmVersion,\n licensed: userOptions.license !== undefined || false,\n copyrightOwner: \"CodeDrifters\",\n release: false,\n\n /**\n * Don't add sample code.\n */\n sampleCode: false,\n\n /**\n * CDK versions sourced from the configulator-managed catalog.\n */\n cdkVersion: VERSION.AWS_CDK_LIB_VERSION,\n cdkCliVersion: VERSION.AWS_CDK_CLI_VERSION,\n\n ...(useJest\n ? {\n /**\n * Make sure jest config is stored outside of package.json and use\n * SWC for faster compilation (matches TypeScriptProject).\n */\n jestOptions: {\n configFilePath: \"jest.config.json\",\n jestConfig: {\n roots: [`<rootDir>/src`],\n transform: {\n [\"^.+\\\\.[t]sx?$\"]: new Transform(\"@swc/jest\"),\n },\n moduleFileExtensions: [\"js\", \"ts\"],\n },\n },\n devDeps: [\"@swc/jest\", \"@swc/core\"] as Array<string>,\n }\n : {\n jest: false,\n devDeps: [] as Array<string>,\n }),\n\n /**\n * Turn on prettier formatting.\n */\n prettier: true,\n\n /**\n * Don't package test files.\n */\n npmIgnoreOptions: {\n ignorePatterns: [\"*.spec.*\", \"*.test.*\"],\n },\n\n /**\n * Options for the automated dependency upgrade task / workflow.\n * Exclude any packages managed by the parent project's default catalog\n * so the catalog stays the source of truth.\n */\n depsUpgrade: true,\n depsUpgradeOptions: {\n workflow: false,\n exclude: Object.keys(pnpmWorkspace?.defaultCatalog || {}),\n workflowOptions: {\n schedule: UpgradeDependenciesSchedule.WEEKLY,\n },\n cooldown: 1,\n },\n\n /**\n * Only release when the package source content or package.json changes.\n */\n releaseTrigger: ReleaseTrigger.continuous({\n paths: [\n `${userOptions.outdir}/src/**`,\n `${userOptions.outdir}/package.json`,\n ],\n }),\n };\n\n /*************************************************************************\n *\n * Merge defaults into user options\n *\n ************************************************************************/\n\n const options: AwsCdkProjectOptions & awscdk.AwsCdkTypeScriptAppOptions =\n merge(defaultOptions, userOptions);\n\n super(options);\n\n /**\n * Use catalog version for @types/node so all packages share a single\n * pinned version.\n */\n this.addDevDeps(\"@types/node@catalog:\");\n\n /**\n * Exclude test files from the main tsconfig only (not tsconfig.dev) so\n * tsc --build compiles only library code (avoids pulling in test-runner\n * types e.g. Vitest/Vite). ESLint and tests still use tsconfig.dev which\n * includes test files.\n */\n this.tsconfig?.addExclude(\"**/*.test.*\");\n this.tsconfig?.addExclude(\"**/*.spec.*\");\n\n /**\n * When using Jest, remove ts-jest since we use @swc/jest.\n * When using Vitest, add the Vitest component (test task + config + deps).\n */\n if (testRunner === TestRunner.VITEST) {\n new Vitest(this, {\n config: {\n include: [\"src/**/*.{test,spec}.?(c|m)[jt]s?(x)\"],\n ...options.vitestOptions?.config,\n },\n ...options.vitestOptions,\n });\n } else {\n this.deps.removeDependency(\"ts-jest\");\n }\n\n /**\n * Specify package manager in package.json.\n */\n this.package.file.addOverride(\n \"packageManager\",\n `pnpm@${options.pnpmVersion}`,\n );\n\n /**\n * Allow test files to use devDependencies. Projen disables the rule for\n * `tests/*` only; we colocate tests next to source so we extend it.\n */\n this.eslint?.addOverride({\n files: [\"**/*.test.*\", \"**/*.spec.*\"],\n rules: {\n \"import/no-extraneous-dependencies\": \"off\",\n },\n });\n\n /**\n * Some standard ignores for all projects.\n */\n this.gitignore?.addPatterns(\".DS_Store\", \"test-reports\", \"cdk.out\");\n this.npmignore?.addPatterns(\"*.spec.*\", \"*.test.*\", \"__fixtures__\");\n\n /**\n * Always create the AwsDeploymentConfig so the synth task is rewritten\n * consistently. AwsDeploymentTarget instances will register themselves\n * onto this config below.\n */\n new AwsDeploymentConfig(this);\n\n /**\n * Wire up deployment targets supplied via constructor options.\n */\n (options.deploymentTargets ?? []).forEach((targetOptions) =>\n this.addDeploymentTarget(targetOptions),\n );\n\n /**\n * Wire up deploy workflows. If `deployWorkflows` is undefined, derive one\n * workflow per unique awsStageType present in the deployment targets.\n * An explicit empty array opts out of auto-derivation.\n */\n const targetsForAutoDerive =\n AwsDeploymentConfig.of(this)?.awsDeploymentTargets ?? [];\n const deployWorkflows =\n options.deployWorkflows ??\n Array.from(new Set(targetsForAutoDerive.map((t) => t.awsStageType))).map(\n (awsStageType): DeployWorkflowOptions => ({\n awsStageType,\n buildWorkflow: options.sharedBuildWorkflow,\n }),\n );\n deployWorkflows.forEach(\n (workflowOptions) => new AwsDeployWorkflow(this, workflowOptions),\n );\n\n /**\n * Optional teardown workflow. Attached to the parent MonorepoProject so\n * it renders once per repo regardless of how many AwsCdkProjects exist.\n */\n if (options.teardownWorkflow) {\n new AwsTeardownWorkflow(parent, options.teardownWorkflow);\n }\n\n /**\n * If turbo is active in the parent project, configure it here.\n */\n const turboActive = TurboRepo.of(parent) !== undefined;\n if (turboActive) {\n const turbo = new TurboRepo(this);\n // `compileTask` is inactive for awscdk apps (no steps), so push CDK\n // build artifacts onto post-compile outputs where they actually render.\n turbo.postCompileTask?.outputs.push(\"dist/**\");\n turbo.postCompileTask?.inputs.push(\"src/**\");\n }\n\n /**\n * AI agent configuration — opt-in per project. Does not propagate from\n * the parent MonorepoProject so sub-projects don't render duplicate\n * `.cursor/` / `.claude/` / `CLAUDE.md` files into their own outdir.\n */\n if (\n options.agentConfig === true ||\n typeof options.agentConfig === \"object\"\n ) {\n new AgentConfig(\n this,\n typeof options.agentConfig === \"object\" ? options.agentConfig : {},\n );\n }\n\n /**\n * Add reset task if enabled.\n */\n if (options.resetTask !== false) {\n const defaultResetTaskOptions: ResetTaskOptions = {\n pathsToRemove: [\n \"node_modules\",\n \"dist\",\n \"lib\",\n \"cdk.out\",\n \"coverage\",\n \"test-reports\",\n \".turbo\",\n \"tsconfig.tsbuildinfo\",\n this.artifactsDirectory,\n ],\n };\n const userResetTaskOptions = options.resetTaskOptions ?? {};\n const resetTaskOptions: ResetTaskOptions = merge(\n defaultResetTaskOptions,\n {\n ...userResetTaskOptions,\n pathsToRemove: [\n ...(defaultResetTaskOptions.pathsToRemove ?? []),\n ...(userResetTaskOptions.pathsToRemove ?? []),\n ],\n },\n );\n new ResetTask(this, resetTaskOptions);\n }\n\n /**\n * Route dependency installation through the parent MonorepoProject so the\n * workspace install handles everything in one pass.\n */\n /* @ts-ignore access private method */\n const originalResolve = this.package.resolveDepsAndWritePackageJson;\n /* @ts-ignore access private method */\n this.package.installDependencies = () => {\n parent.requestInstallDependencies({\n resolveDepsAndWritePackageJson: () =>\n originalResolve.apply(this.package),\n });\n };\n /* @ts-ignore access private method */\n this.package.resolveDepsAndWritePackageJson = () => {};\n }\n\n /**\n * Add an AWS deployment target to this project after construction. The\n * target is registered on the existing `AwsDeploymentConfig` and immediately\n * available for `AwsDeployWorkflow` consumption.\n */\n public addDeploymentTarget(\n options: AwsDeploymentTargetOptions,\n ): AwsDeploymentTarget {\n return new AwsDeploymentTarget(this, options);\n }\n}\n","// eslint-disable-next-line import/no-extraneous-dependencies\nimport {\n AWS_STAGE_TYPE,\n AwsStageType,\n DEPLOYMENT_TARGET_ROLE,\n DeploymentTargetRoleType,\n} from \"@codedrifters/utils\";\nimport { Component } from \"projen\";\nimport { AwsCdkTypeScriptApp } from \"projen/lib/awscdk\";\nimport { BuildWorkflow, BuildWorkflowOptions } from \"projen/lib/build\";\nimport { GitHub, WorkflowSteps } from \"projen/lib/github\";\nimport { JobPermission, JobStep } from \"projen/lib/github/workflows-model\";\nimport { ValueOf } from \"type-fest\";\nimport { AwsDeploymentConfig } from \"../aws\";\nimport { addBuildCompleteJob } from \"./build-complete-job\";\nimport { AwsDeploymentTarget } from \"../aws/aws-deployment-target\";\nimport { GitBranch } from \"../git\";\nimport { MonorepoProject } from \"../projects\";\nimport { ROOT_CI_TASK_NAME, TurboRepo } from \"../turbo\";\nimport { VERSION } from \"../versions\";\n\nexport const PROD_DEPLOY_NAME = \"prod-deploy\";\n\nexport interface DeployWorkflowOptions {\n /**\n * What type of deploy is this workflow for?\n *\n * @default AWS_STAGE_TYPE.DEV\n */\n readonly awsStageType?: ValueOf<typeof AWS_STAGE_TYPE>;\n\n /**\n * Optionally feed a list of targets to deploy to.\n *\n * @default discovers all targets using stageType\n */\n readonly awsDeploymentTargets?: Array<AwsDeploymentTarget>;\n\n /**\n * Existing workflow, useful if we're tacking deployments onto an existing\n * build workflow\n */\n readonly buildWorkflow?: BuildWorkflow;\n\n /**\n * Options for the build workflow, if no build workflow is provided.\n */\n readonly buildWorkflowOptions?: Partial<BuildWorkflowOptions>;\n\n /**\n * Projects that should complete deployment before this one starts.\n */\n readonly deployAfterTargets?: Array<AwsDeploymentTarget>;\n}\n\nexport class AwsDeployWorkflow extends Component {\n public static of(\n project: AwsCdkTypeScriptApp,\n buildWorkflow: BuildWorkflow,\n ): AwsDeployWorkflow | undefined {\n const isDefined = (c: Component): c is AwsDeployWorkflow =>\n c instanceof AwsDeployWorkflow && c.buildWorkflow === buildWorkflow;\n return project.components.find(isDefined);\n }\n\n /**\n * The root project for this deploy workflow. Must be a monorepo project.\n */\n private rootProject: MonorepoProject;\n\n /**\n * What type of deploy is this workflow for?\n */\n public awsStageType: AwsStageType;\n\n /**\n * AWS environment type, such as primary or secondary.\n *\n * @deprecated Use deployment target role terminology elsewhere. This property is maintained for backward compatibility.\n * @default 'primary' (this is the only type supported currently)\n */\n public awsEnvironmentType: DeploymentTargetRoleType =\n DEPLOYMENT_TARGET_ROLE.PRIMARY;\n\n /**\n * The list of targets to deploy to.\n */\n readonly awsDeploymentTargets: Array<AwsDeploymentTarget>;\n\n /**\n * Hold the deploy workflow so we can add to it in preSynth\n */\n public buildWorkflow: BuildWorkflow;\n\n /**\n * Was this workflow created externally?\n */\n public externalWorkflow: boolean;\n\n /**\n * Projects that should complete deployment before this one starts.\n */\n public deployAfterTargets: Array<AwsDeploymentTarget>;\n\n constructor(\n public project: AwsCdkTypeScriptApp,\n public options: DeployWorkflowOptions = {},\n ) {\n super(project);\n\n /***************************************************************************\n *\n * Root project check\n *\n * Detect the root project and ensure it's of type MonorepoProject.\n *\n **************************************************************************/\n\n if (!(project.root instanceof MonorepoProject)) {\n throw new Error(\n \"AwsDeployWorkflow requires the root project to be a MonorepoProject\",\n );\n }\n\n this.rootProject = project.root;\n\n /***************************************************************************\n *\n * GitHub Check\n *\n * Make sure github config is active in the project. This is to ensure all\n * workflows will be output properly during synth.\n *\n **************************************************************************/\n\n const github = GitHub.of(this.rootProject);\n\n if (!github) {\n throw new Error(\n \"AwsDeployWorkflow requires a GitHub component in the root project\",\n );\n }\n\n /***************************************************************************\n *\n * TurboRepo Check\n *\n * If turbo is enabled, we may need the options later in this file.\n *\n **************************************************************************/\n\n const turbo = TurboRepo.of(this.rootProject);\n const buildWorkflowOptions: Partial<BuildWorkflowOptions> =\n turbo?.remoteCacheOptions\n ? TurboRepo.buildWorkflowOptions(turbo.remoteCacheOptions)\n : {};\n\n /***************************************************************************\n *\n * Workflow Deploy Type\n *\n * What type of environments are we deploying into? We'll default to dev to\n * be safe.\n *\n **************************************************************************/\n\n this.awsStageType = options.awsStageType ?? AWS_STAGE_TYPE.DEV;\n\n /***************************************************************************\n *\n * Workflow Deploy Targets\n *\n * Use provided targets or discover them based on the deploy type. Only\n * include targets that are marked for CI/CD.\n *\n **************************************************************************/\n\n this.awsDeploymentTargets =\n options.awsDeploymentTargets ??\n AwsDeploymentConfig.of(project)?.awsDeploymentTargets.filter(\n (target) =>\n target.awsStageType === this.awsStageType && target.ciDeployment,\n ) ??\n [];\n\n this.deployAfterTargets = options.deployAfterTargets ?? [];\n\n /***************************************************************************\n *\n * Build Workflow Options\n *\n * Can't use the options if an existing workflow was passed in.\n *\n **************************************************************************/\n\n if (options.buildWorkflow && options.buildWorkflowOptions) {\n throw new Error(\n \"Cannot provide both buildWorkflow and buildWorkflowOptions\",\n );\n }\n\n this.externalWorkflow = !!options.buildWorkflow;\n\n /***************************************************************************\n *\n * Build Workflow\n *\n * Create a workflow either based on input or from scratch.\n *\n **************************************************************************/\n\n this.buildWorkflow =\n options.buildWorkflow ??\n new BuildWorkflow(this.rootProject, {\n /**\n * Name based on project and environment.\n */\n name:\n options.buildWorkflowOptions?.name ??\n [\n \"deploy\",\n project.name,\n this.awsStageType,\n this.awsEnvironmentType,\n ].join(\"-\"),\n\n /**\n * Use the root projects build task.\n */\n buildTask: this.rootProject.buildTask,\n\n /**\n * Use push triggers based n the branch config for each environment.\n */\n workflowTriggers: {\n push: {\n branches: [\n ...this.awsDeploymentTargets.flatMap((t) =>\n t.branches.map((b) => b.branch),\n ),\n ],\n },\n workflowDispatch: {},\n ...options.buildWorkflowOptions?.workflowTriggers,\n },\n\n /**\n * Never allow mutations for deploys. This should have been handled\n * during build.\n */\n mutableBuild: false,\n\n /**\n * Do this pre-merge of permissions and build steps\n */\n ...options.buildWorkflowOptions,\n\n /**\n * Set GIT_BRANCH_NAME so Turborepo remote cache hashes match between local and CI.\n */\n env: {\n GIT_BRANCH_NAME: \"${{ github.head_ref || github.ref_name }}\",\n ...options.buildWorkflowOptions?.env,\n ...buildWorkflowOptions?.env,\n },\n\n /**\n * Some additional permissions may be required when turbo's involved.\n */\n permissions: {\n ...options.buildWorkflowOptions?.permissions,\n ...buildWorkflowOptions?.permissions,\n },\n\n /**\n * Assemble all pre-build steps\n */\n preBuildSteps: [\n ...this.setupPnpm(),\n ...this.setupNode(),\n {\n name: \"Install dependencies\",\n run: \"pnpm i --no-frozen-lockfile\",\n },\n ...(options.buildWorkflowOptions?.preBuildSteps ?? []),\n ...(buildWorkflowOptions?.preBuildSteps ?? []),\n ],\n });\n\n /***************************************************************************\n *\n * Add Deployments to workflow\n *\n **************************************************************************/\n\n const buildJobName = (target: AwsDeploymentTarget) => {\n return [\n target.awsStageType,\n target.deploymentTargetRole,\n \"deploy\",\n target.project.name,\n target.account,\n target.region,\n ].join(\"-\");\n };\n\n this.awsDeploymentTargets.forEach((target) => {\n const deployJobName = buildJobName(target);\n\n // Build the branch filter condition\n const branchFilterCondition = this.buildBranchFilterCondition(\n target.branches,\n );\n\n // Combine with the existing build mutation check\n const jobCondition = branchFilterCondition\n ? \"${{ \" +\n [\n \"!needs.build.outputs.self_mutation_happened\",\n `(${branchFilterCondition})`,\n ].join(\" && \") +\n \" }}\"\n : \"${{ !needs.build.outputs.self_mutation_happened }}\";\n\n this.buildWorkflow.addPostBuildJob(deployJobName, {\n name: `Deploy ${this.project.name} ${target.awsStageType}/${target.deploymentTargetRole}/${target.account}/${target.region}`,\n needs: [\n \"build\",\n ...this.deployAfterTargets.map((p) => {\n return buildJobName(p);\n }),\n ],\n runsOn: [\"ubuntu-latest\"],\n permissions: {\n contents: JobPermission.READ,\n idToken: JobPermission.WRITE,\n },\n concurrency: deployJobName,\n if: jobCondition,\n steps: [...this.deploySteps(target)],\n });\n });\n\n /**\n * Append the \"complete\" gate job (ADR 0004) so this workflow has a single\n * required status check.\n */\n addBuildCompleteJob(this.buildWorkflow);\n }\n\n public setupNode = (): Array<JobStep> => {\n return [\n {\n name: \"Setup Node\",\n uses: `actions/setup-node@${VERSION.SETUP_NODE_ACTION_VERSION}`,\n with: {\n [\"node-version\"]: VERSION.NODE_WORKFLOWS,\n },\n // occasionally this step fails due to internal issues at github\n timeoutMinutes: 1,\n },\n ];\n };\n\n public setupPnpm = (): Array<JobStep> => {\n return [\n {\n name: \"Setup PNPM\",\n uses: `pnpm/action-setup@${VERSION.PNPM_ACTION_SETUP_VERSION}`,\n with: {\n version: VERSION.PNPM_VERSION,\n },\n },\n ];\n };\n\n /**\n * Builds a GitHub Actions condition string that checks if the current branch\n * matches any of the provided branch patterns.\n *\n * Handles both exact matches (e.g., \"main\") and glob patterns (e.g., \"feature/*\").\n * Also allows workflow_dispatch (manual runs) to proceed.\n *\n * @param branches Array of GitBranch objects with branch patterns\n * @returns Condition string or empty string if no branches provided\n */\n private buildBranchFilterCondition = (branches: Array<GitBranch>): string => {\n if (!branches || branches.length === 0) {\n return \"\";\n }\n\n const conditions: Array<string> = [];\n\n // Always allow workflow_dispatch (manual workflow runs)\n conditions.push(\"github.event_name == 'workflow_dispatch'\");\n\n for (const branch of branches) {\n const branchPattern = branch.branch;\n\n // Handle glob patterns (e.g., \"feature/*\")\n if (branchPattern.includes(\"*\")) {\n // Replace * with proper startsWith check\n const prefix = branchPattern.replace(/\\*.*$/, \"\");\n conditions.push(`startsWith(github.ref, 'refs/heads/${prefix}')`);\n // PR support, unprefixed branch names\n conditions.push(`startsWith(github.head_ref, '${prefix}')`);\n } else {\n // Exact match\n conditions.push(`github.ref == 'refs/heads/${branchPattern}'`);\n }\n }\n\n /**\n * Combine all conditions with OR\n */\n return conditions.join(\" || \");\n };\n\n private deploySteps = (target: AwsDeploymentTarget): Array<JobStep> => {\n const {\n awsStageType,\n deploymentTargetRole,\n account,\n region,\n ciDeploymentConfig,\n awsDeploymentConfig,\n } = target;\n const { roleArn, stackPattern } = ciDeploymentConfig ?? {};\n const { rootCdkOut } = awsDeploymentConfig;\n\n return [\n ...this.setupPnpm(),\n ...this.setupNode(),\n\n /**\n * Install CDK\n */\n {\n name: \"Install CDK\",\n run: \"pnpm add aws-cdk\",\n },\n\n /**\n * Configure AWS creds.\n */\n {\n name: `AWS Creds ${awsStageType}/${deploymentTargetRole}/${account}/${region}`,\n uses: \"aws-actions/configure-aws-credentials@v4\",\n with: {\n \"role-to-assume\": roleArn,\n \"aws-region\": region,\n \"role-duration-seconds\": 900, // 15 minutes\n },\n },\n\n /**\n * Run CDK Deploy\n */\n {\n name: `Deploy ${awsStageType}/${deploymentTargetRole}/${account}/${region}`,\n run: `pnpm dlx aws-cdk deploy --no-rollback --require-approval=never --app=${rootCdkOut} \"${stackPattern}\"`,\n },\n ];\n };\n\n preSynthesize(): void {\n /**\n * Ensure turbo is active when needed.\n */\n if (!this.externalWorkflow && TurboRepo.of(this.rootProject)) {\n this.buildWorkflow.addPostBuildSteps(\n {\n name: \"Build Sub Projects\",\n run: `npx projen ${ROOT_CI_TASK_NAME}`,\n },\n WorkflowSteps.uploadArtifact({\n name: \"Upload Turbo runs\",\n if: \"always()\",\n continueOnError: true,\n with: {\n name: \"turbo-runs\",\n path: \".turbo/runs\",\n },\n }),\n );\n }\n\n super.preSynthesize();\n }\n}\n","import { Component } from \"projen\";\nimport { GitHub, GithubWorkflow } from \"projen/lib/github\";\nimport { JobPermission } from \"projen/lib/github/workflows-model\";\nimport { AwsDeploymentTarget } from \"../aws/aws-deployment-target\";\nimport { MonorepoProject } from \"../projects/monorepo-project\";\n\n/**\n * Default branch-delete patterns that trigger the teardown workflow.\n */\nexport const DEFAULT_TEARDOWN_BRANCH_PATTERNS: ReadonlyArray<string> = [\n \"feat/*\",\n \"fix/*\",\n \"feature/*\",\n];\n\n/**\n * Options for {@link AwsTeardownWorkflow}.\n */\nexport interface AwsTeardownWorkflowOptions {\n /**\n * Targets to scan for orphaned CloudFormation stacks.\n */\n readonly awsDestructionTargets: Array<AwsDeploymentTarget>;\n\n /**\n * Name of the tag containing the repo name. Used to find CloudFormation\n * stacks associated with this repo.\n */\n readonly repoTagName: string;\n\n /**\n * Name of the tag containing the stage type (e.g. dev, stage, prod).\n */\n readonly stageTypeTagName: string;\n\n /**\n * Name of the tag containing the environment type (e.g. primary, secondary).\n */\n readonly environmentTypeTagName: string;\n\n /**\n * Name of the tag where branch names are stored. Used to determine if a\n * stack is orphaned (no matching branch).\n */\n readonly branchNameTagName: string;\n\n /**\n * Branch patterns whose deletion triggers the teardown workflow.\n *\n * @default [\"feat/*\", \"fix/*\", \"feature/*\"]\n */\n readonly deleteBranchPatterns?: Array<string>;\n}\n\n/**\n * Resolve the set of branch-delete patterns to wire into the workflow's\n * `on.delete.branches` trigger.\n *\n * Precedence:\n * 1. Explicit `deleteBranchPatterns` from options.\n * 2. Wildcard patterns (containing `*`) derived from the destruction\n * targets' configured branches, deduped.\n * 3. {@link DEFAULT_TEARDOWN_BRANCH_PATTERNS} as a last-resort fallback.\n */\nconst resolveBranchPatterns = (\n explicit: Array<string> | undefined,\n targets: ReadonlyArray<AwsDeploymentTarget>,\n): Array<string> => {\n if (explicit && explicit.length > 0) {\n return [...explicit];\n }\n\n const derived = Array.from(\n new Set(\n targets\n .flatMap((target) => target.branches.map((b) => b.branch))\n .filter((branch): branch is string => typeof branch === \"string\")\n .filter((branch) => branch.includes(\"*\")),\n ),\n );\n\n if (derived.length > 0) {\n return derived;\n }\n\n return [...DEFAULT_TEARDOWN_BRANCH_PATTERNS];\n};\n\n/**\n * Scheduled GitHub Actions workflow that tears down orphaned CloudFormation\n * stacks whose associated branch no longer exists.\n */\nexport class AwsTeardownWorkflow extends Component {\n constructor(\n public rootProject: MonorepoProject,\n options: AwsTeardownWorkflowOptions,\n ) {\n super(rootProject);\n\n const {\n awsDestructionTargets,\n repoTagName,\n stageTypeTagName,\n environmentTypeTagName,\n branchNameTagName,\n deleteBranchPatterns,\n } = options;\n\n if (!repoTagName) {\n throw new Error(\"AwsTeardownWorkflow requires `repoTagName`\");\n }\n if (!stageTypeTagName) {\n throw new Error(\"AwsTeardownWorkflow requires `stageTypeTagName`\");\n }\n if (!environmentTypeTagName) {\n throw new Error(\"AwsTeardownWorkflow requires `environmentTypeTagName`\");\n }\n if (!branchNameTagName) {\n throw new Error(\"AwsTeardownWorkflow requires `branchNameTagName`\");\n }\n\n if (!(rootProject instanceof MonorepoProject)) {\n throw new Error(\n \"AwsTeardownWorkflow requires the root project to be a MonorepoProject\",\n );\n }\n\n const github = GitHub.of(this.rootProject);\n\n if (!github) {\n throw new Error(\n \"AwsTeardownWorkflow requires a GitHub component in the root project\",\n );\n }\n\n const branchPatterns = resolveBranchPatterns(\n deleteBranchPatterns,\n awsDestructionTargets,\n );\n\n const workflow = new GithubWorkflow(github, \"teardown-dev\");\n workflow.on({\n workflowDispatch: {},\n schedule: [\n {\n cron: \"32 6 * * *\",\n },\n ],\n delete: {\n branches: branchPatterns,\n },\n });\n\n awsDestructionTargets.forEach((target) => {\n const {\n awsStageType,\n deploymentTargetRole,\n account,\n region,\n ciDeploymentConfig,\n } = target;\n const { roleArn } = ciDeploymentConfig ?? {};\n\n workflow.addJob(\n `teardown-${awsStageType}-${deploymentTargetRole}-${account}-${region}`.toLowerCase(),\n {\n name: `Teardown Stacks in ${awsStageType}/${deploymentTargetRole}/${account}/${region}`,\n runsOn: [\"ubuntu-latest\"],\n permissions: {\n contents: JobPermission.READ,\n idToken: JobPermission.WRITE,\n },\n env: {\n REPO: \"${{ github.repository }}\",\n REGIONS: [region].join(\" \"),\n },\n steps: [\n {\n name: `AWS Creds ${account}/${region}`,\n uses: \"aws-actions/configure-aws-credentials@v6\",\n with: {\n \"role-to-assume\": roleArn,\n \"aws-region\": region,\n \"role-duration-seconds\": 900,\n },\n },\n {\n name: \"Fetch All Branches\",\n id: \"fetch_branches\",\n uses: \"actions/github-script@v9\",\n with: {\n script: [\n \"const all = await github.paginate(github.rest.repos.listBranches, {\",\n \" owner: context.repo.owner,\",\n \" repo: context.repo.repo,\",\n \" per_page: 100\",\n \"});\",\n \"const names = all.map(b => b.name);\",\n \"console.log(`Found branches: ${names}`);\",\n 'core.setOutput(\"json\", JSON.stringify(names));',\n ].join(\"\\n\"),\n },\n },\n {\n name: \"Save Branches to File\",\n run: [\n 'echo \"Saving branches to file\"',\n \"echo '${{ steps.fetch_branches.outputs.json }}' | jq -r '.[]' | sort -u > branches.txt\",\n 'echo \"Branches:\"',\n \"cat branches.txt\",\n ].join(\"\\n\"),\n },\n {\n name: \"Find Stacks by Tag\",\n id: \"find_stacks\",\n run: [\n \"set -euo pipefail\",\n \": > candidates.txt # columns: arn region branchTag\",\n \"# Build tag filters\",\n `TAG_FILTERS=( \"Key=${repoTagName},Values=$REPO\" )`,\n `TAG_FILTERS+=( \"Key=${stageTypeTagName},Values=${awsStageType}\" )`,\n `TAG_FILTERS+=( \"Key=${environmentTypeTagName},Values=${deploymentTargetRole}\" )`,\n \"for r in $REGIONS; do\",\n ` echo \"Scanning region: $r\"`,\n \" aws resourcegroupstaggingapi get-resources \\\\\",\n ' --region \"$r\" \\\\',\n ' --resource-type-filters \"cloudformation:stack\" \\\\',\n ' --tag-filters \"${TAG_FILTERS[@]}\" \\\\',\n ` | jq -r --arg r \"$r\" '`,\n \" .ResourceTagMappingList[]\",\n \" | . as $res\",\n ` | ($res.Tags[] | select(.Key==\"${branchNameTagName}\") | .Value) as $branch`,\n ' | [$res.ResourceARN, $r, ($branch // \"\")]',\n \" | @tsv\",\n \" ' >> candidates.txt\",\n \"done\",\n \"echo 'Tagged stacks:'\",\n `(echo -e \"ARN\\\\tREGION\\\\tBRANCH\"; cat candidates.txt) | column -t -s $'\\\\t'`,\n ].join(\"\\n\"),\n },\n {\n name: \"Determine Orphan Stacks (No Matching Branch)\",\n run: [\n \"set -euo pipefail\",\n \": > orphans.txt # arn region branch\",\n \"while IFS=$'\\\\t' read -r arn region branch; do\",\n ' [ -z \"$arn\" ] && continue',\n ' if [ -z \"$branch\" ]; then',\n \" # If no Branch tag, treat as not-a-preview; skip\",\n \" continue\",\n \" fi\",\n ' if ! grep -Fxq \"$branch\" branches.txt; then',\n ' echo -e \"$arn\\\\t$region\\\\t$branch\" >> orphans.txt',\n \" fi\",\n \"done < candidates.txt\",\n \"\",\n \"if [ -s orphans.txt ]; then\",\n ' echo \"Orphan stacks (no matching branch):\"',\n \" (echo -e \\\"ARN\\\\tREGION\\\\tBRANCH\\\"; cat orphans.txt) | column -t -s $'\\\\t'\",\n \"else\",\n ' echo \"No orphan stacks found.\"',\n \"fi\",\n ].join(\"\\n\"),\n },\n {\n name: \"Delete Orphan Stacks\",\n if: \"hashFiles('orphans.txt') != ''\",\n run: [\n \"set -euo pipefail\",\n \"while IFS=$'\\\\t' read -r arn region branch; do\",\n ' [ -z \"$arn\" ] && continue',\n \" stack_name=$(cut -d'/' -f2 <<<\\\"$arn\\\")\",\n ' echo \"Deleting $stack_name (branch=$branch) in $region\"',\n ' aws cloudformation delete-stack --region \"$region\" --stack-name \"$stack_name\" || true',\n \"done < orphans.txt\",\n ].join(\"\\n\"),\n },\n ],\n },\n );\n });\n }\n}\n","import { SampleFile } from \"projen\";\nimport { AstroIntegrationSpec } from \"../astro/astro-config-options\";\nimport { TurboRepo } from \"../turbo\";\nimport { VERSION } from \"../versions\";\nimport { AstroProject, AstroProjectOptions } from \"./astro-project\";\n\n/**\n * A single Starlight social icon link.\n */\nexport interface StarlightSocialLink {\n readonly icon: string;\n readonly label: string;\n readonly href: string;\n}\n\n/**\n * Starlight logo configuration.\n */\nexport interface StarlightLogo {\n readonly src: string;\n readonly alt?: string;\n}\n\n/**\n * Starlight edit-link configuration.\n */\nexport interface StarlightEditLink {\n readonly baseUrl: string;\n}\n\n/**\n * Sidebar item accepted by Starlight's `sidebar` config. Covers the four\n * common shapes: link, group with nested items, autogenerated group, and\n * internal slug reference.\n */\nexport type StarlightSidebarItem =\n | {\n readonly label: string;\n readonly link: string;\n readonly badge?:\n | string\n | { readonly text: string; readonly variant?: string };\n }\n | {\n readonly label: string;\n readonly items: ReadonlyArray<StarlightSidebarItem>;\n }\n | {\n readonly label: string;\n readonly autogenerate: {\n readonly directory: string;\n readonly collapsed?: boolean;\n };\n }\n | { readonly label: string; readonly slug: string };\n\n/**\n * Configuration options for StarlightProject.\n */\nexport interface StarlightProjectOptions extends AstroProjectOptions {\n /**\n * Starlight site title (required).\n */\n readonly starlightTitle: string;\n\n /**\n * Starlight site description.\n */\n readonly starlightDescription?: string;\n\n /**\n * Social links rendered in the Starlight header.\n */\n readonly social?: ReadonlyArray<StarlightSocialLink>;\n\n /**\n * Sidebar config (passed through verbatim). When omitted, Starlight\n * autogenerates the sidebar from the `src/content/docs/` tree.\n */\n readonly sidebar?: ReadonlyArray<StarlightSidebarItem>;\n\n /**\n * Custom CSS files loaded by Starlight.\n */\n readonly customCss?: ReadonlyArray<string>;\n\n /**\n * Site logo displayed in the Starlight header.\n */\n readonly logo?: StarlightLogo;\n\n /**\n * \"Edit this page\" link configuration.\n */\n readonly editLink?: StarlightEditLink;\n\n /**\n * @astrojs/starlight package version.\n *\n * @default VERSION.STARLIGHT_VERSION\n */\n readonly starlightVersion?: string;\n\n /**\n * sharp package version (required peer for Starlight's image pipeline).\n *\n * @default VERSION.SHARP_VERSION\n */\n readonly sharpVersion?: string;\n\n /**\n * Emit sample Starlight content (`src/content/docs/index.mdx`,\n * `src/content/config.ts`).\n *\n * @default false\n */\n readonly sampleContent?: boolean;\n}\n\n/**\n * Docs site scaffolded on top of {@link AstroProject} using the\n * Starlight Astro integration.\n */\nexport class StarlightProject extends AstroProject {\n constructor(userOptions: StarlightProjectOptions) {\n const starlightConfig = buildStarlightConfig(userOptions);\n const starlightSpec: AstroIntegrationSpec = {\n name: \"starlight\",\n importPath: \"@astrojs/starlight\",\n defaultImport: true,\n args: JSON.stringify(starlightConfig, null, 2),\n };\n\n /**\n * Prepend the Starlight integration so it appears first in the\n * rendered `integrations` array (matches Starlight docs convention).\n */\n /**\n * Exclude Starlight and sharp from projen's per-package ncu upgrade\n * workflow — same pattern AstroProject uses for `astro` — so\n * VERSION.STARLIGHT_VERSION / VERSION.SHARP_VERSION remain the single\n * source of truth.\n */\n const mergedOptions: AstroProjectOptions = {\n ...userOptions,\n integrations: [starlightSpec, ...(userOptions.integrations ?? [])],\n depsUpgradeOptions: {\n ...userOptions.depsUpgradeOptions,\n exclude: [\n ...(userOptions.depsUpgradeOptions?.exclude ?? []),\n \"@astrojs/starlight\",\n \"sharp\",\n ],\n },\n };\n\n super(mergedOptions);\n\n const starlightVersion =\n userOptions.starlightVersion ?? VERSION.STARLIGHT_VERSION;\n const sharpVersion = userOptions.sharpVersion ?? VERSION.SHARP_VERSION;\n\n this.addDeps(\n `@astrojs/starlight@${starlightVersion}`,\n `sharp@${sharpVersion}`,\n );\n\n /**\n * Extend turbo compile inputs with Starlight's content collection tree.\n */\n const turbo = TurboRepo.of(this);\n if (turbo?.compileTask) {\n turbo.compileTask.inputs.push(\"src/content/**\");\n }\n\n /**\n * Optional sample content.\n */\n if (userOptions.sampleContent === true) {\n new SampleFile(this, \"src/content/docs/index.mdx\", {\n contents: DEFAULT_INDEX_MDX,\n });\n new SampleFile(this, \"src/content/config.ts\", {\n contents: DEFAULT_CONTENT_CONFIG_TS,\n });\n }\n }\n}\n\n/**\n * Build the JSON-serializable Starlight config object from user options.\n */\nfunction buildStarlightConfig(\n options: StarlightProjectOptions,\n): Record<string, unknown> {\n const config: Record<string, unknown> = {\n title: options.starlightTitle,\n };\n if (options.starlightDescription !== undefined) {\n config.description = options.starlightDescription;\n }\n if (options.social !== undefined) {\n config.social = options.social;\n }\n if (options.sidebar !== undefined) {\n config.sidebar = options.sidebar;\n }\n if (options.customCss !== undefined) {\n config.customCss = options.customCss;\n }\n if (options.logo !== undefined) {\n config.logo = options.logo;\n }\n if (options.editLink !== undefined) {\n config.editLink = options.editLink;\n }\n return config;\n}\n\nconst DEFAULT_INDEX_MDX = `---\ntitle: Welcome\ndescription: Starlight-powered documentation site.\n---\n\n# Hello, Starlight!\n\nEdit \\`src/content/docs/index.mdx\\` to replace this page.\n`;\n\nconst DEFAULT_CONTENT_CONFIG_TS = `import { defineCollection } from \"astro:content\";\nimport { docsSchema } from \"@astrojs/starlight/schema\";\n\nexport const collections = {\n docs: defineCollection({ schema: docsSchema() }),\n};\n`;\n","import { relative } from \"node:path\";\nimport { Component } from \"projen\";\nimport { TypeScriptProject } from \"projen/lib/typescript\";\nimport { ensureRelativePathStartsWithDot } from \"projen/lib/util/path\";\n\n/*******************************************************************************\n *\n * Update / customize typescript configs for a project.\n *\n * Update typescript paths in tsconfig so we don't have to compile packages to\n * dist in order to see changes.\n *\n ******************************************************************************/\nexport class TypeScriptConfig extends Component {\n constructor(project: TypeScriptProject) {\n super(project);\n\n /**\n * Container for paths to insert at the end.\n */\n let tsPaths = {};\n\n const workspaceDeps = project.deps.all.filter(\n (d) => d.version === \"workspace:*\",\n );\n\n workspaceDeps.forEach((dep) => {\n const subproject = (\n project.root.subprojects as Array<TypeScriptProject>\n ).find((p) => p.package.packageName === dep.name);\n\n if (!subproject) {\n throw new Error(`Could not find subproject ${dep.name} in monorepo.`);\n }\n\n tsPaths = {\n ...tsPaths,\n [dep.name]: [\n ensureRelativePathStartsWithDot(\n relative(project.outdir, subproject.outdir),\n ),\n ],\n };\n });\n\n project.tsconfig?.file.addOverride(\"compilerOptions.paths\", tsPaths);\n project.tsconfigDev?.file.addOverride(\"compilerOptions.paths\", tsPaths);\n }\n}\n"],"mappings":"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ACA;AAAA,QACA;AAAA,QACA;AAAA,QACA;AAAA,QACA;AAAA,QACA;AAAA,QACA;AAAA,QACA;AAAA,QACA;AAAA,QACA;AAAA,QACA;AAAA,QACA;AAAA,QACA;AAAA,QACA;AAAA,QACA;AAAA,QACA;AAAA,QACA;AAAA,QACA;AAAA,QACA;AAAA,QACA;AAAA,QACA;AAAA,QACA;AAAA,QACA;AAAA,QACA;AAAA,QACA;AAAA,QACA;AAAA,QACA;AAAA,QACA;AAAA,QACA;AAAA,QACA;AAAA,QACA;AAAA,QACA;AAAA,QACA;AAAA,QACA;AAAA,QACA;AAAA,QACA;AAAA,QACA;AAAA,QACA;AAAA,QACA;AAAA,QACA;AAAA,QACA;AAAA,QACA;AAAA,QACA;AAAA,QACA;AAAA,QACA;AAAA,QACA;AAAA,QACA;AAAA,QACA;AAAA,QACA;AAAA,QACA;AAAA,QACA;AAAA,QACA;AAAA,QACA;AAAA,QACA;AAAA,QACA;AAAA,QACA;AAAA,QACA;AAAA,QACA;AAAA,QACA;AAAA,QACA;AAAA,QACA;AAAA,QACA;AAAA,QACA;AAAA,QACA;AAAA,QACA;AAAA,QACA;AAAA,QACA;AAAA,QACA;AAAA,QACA;AAAA,QACA;AAAA,QACA;AAAA,QACA;AAAA,QACA;AAAA,QACA;AAAA,QACA;AAAA,QACA;AAAA,QACA;AAAA,QACA;AAAA,QACA;AAAA,QACA;AAAA,QACA;AAAA,QACA;AAAA,QACA;AAAA,QACA;AAAA,QACA;AAAA,QACA;AAAA,QACA;AAAA,QACA;AAAA,QACA;AAAA,QACA;AAAA,QACA;AAAA,QACA;AAAA,QACA;AAAA,QACA;AAAA,QACA;AAAA,QACA;AAAA,QACA;AAAA,QACA;AAAA,QACA;AAAA,QACA;AAAA,QACA;AAAA,QACA;AAAA,QACA;AAAA,QACA;AAAA,QACA;AAAA,QACA;AAAA,QACA;AAAA,QACA;AAAA,QACA;AAAA,QACA;AAAA,QACA;AAAA,QACA;AAAA,QACA;AAAA,QACA;AAAA,QACA;AAAA,QACA;AAAA,MACF,EAAE,KAAK,IAAI;AAAA,MACX,MAAM,CAAC,U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AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;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IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,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ACA;AAAA,QACA;AAAA,QACA;AAAA,QACA;AAAA,QACA;AAAA,QACA;AAAA,QACA;AAAA,QACA;AAAA,QACA;AAAA,QACA;AAAA,QACA;AAAA,QACA;AAAA,QACA;AAAA,QACA;AAAA,QACA;AAAA,QACA;AAAA,QACA;AAAA,QACA;AAAA,QACA;AAAA,QACA;AAAA,QACA;AAAA,QACA;AAAA,QACA;AAAA,QACA;AAAA,QACA;AAAA,QACA;AAAA,QACA;AAAA,QACA;AAAA,QACA;AAAA,QACA;AAAA,QACA;AAAA,QACA;AAAA,QACA;AAAA,QACA;AAAA,QACA;AAAA,QACA;AAAA,QACA;AAAA,QACA;AAAA,QACA;AAAA,QACA;AAAA,QACA;AAAA,QACA;AAAA,QACA;AAAA,QACA;AAAA,QACA;AAAA,QACA;AAAA,QACA;AAAA,QACA;AAAA,QACA;AAAA,QACA;AAAA,QACA;AAAA,QACA;AAAA,QACA;AAAA,QACA;AAAA,QACA;AAAA,QACA;AAAA,QACA;AAAA,QACA;AAAA,QACA;AAAA,QACA;AAAA,QACA;AAAA,QACA;AAAA,QACA;AAAA,QACA;AAAA,QACA;AAAA,QACA;AAAA,QACA;AAAA,QACA;AAAA,MACF,EAAE,KAAK,IAAI;AAAA,MACX,MAAM,CAAC,UAAU;AAAA,IACnB;AAAA,IACA;AAAA,MACE,MAAM;AAAA,MACN,aAAa;AAAA,MACb,OAAO,iBAAiB;AAAA,MACxB,SAAS;AAAA,QACP;AAAA,QACA;AAAA,QACA;AAAA,QACA;AAAA,QACA;AAAA,QACA;AAAA,QACA;AAAA,QACA;AAAA,QACA;AAAA,QACA;AAAA,QACA;AAAA,QACA;AAAA,QACA;AAAA,QACA;AAAA,QACA;AAAA,QACA;AAAA,QACA;AAAA,QACA;AAAA,QACA;AAAA,QACA;AAAA,QACA;AAAA,QACA;AAAA,QACA;AAAA,QACA;AAAA,QACA;AAAA,QACA;AAAA,QACA;AAAA,QACA;AAAA,QACA;AAAA,QACA;AAAA,QACA;AAAA,QACA;AAAA,QACA;AAAA,QACA;AAAA,QACA;AAAA,QACA;AAAA,MACF,EAAE,KAAK,IAAI;AAAA,MACX,MAAM,CAAC,UAAU;AAAA,IACnB;AAAA,EACF;AACF;;;ACzIA,IAAM,mCAAkD;AAAA,EACtD,MAAM;AAAA,EACN,aACE;AAAA,EACF,OAAO,YAAY;AAAA,EACnB,UAAU;AAAA,EACV,WAAW,EAAE,QAAQ,EAAE,SAAS,KAAK,EAAE;AAAA,EACvC,QAAQ;AAAA,IACN;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA,GAAG;AAAA,IACH;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,EACF,EAAE,KAAK,IAAI;AACb;AAGA,IAAM,0BAAsC;AAAA,EAC1C,MAAM;AAAA,EACN,aACE;AAAA,EACF,wBAAwB;AAAA,EACxB,eAAe;AAAA,EACf,SAAS;AAAA,EACT,OAAO;AAAA,EACP,WAAW,EAAE,QAAQ,EAAE,SAAS,KAAK,EAAE;AAAA,EACvC,cAAc;AAAA,IACZ;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,EACF,EAAE,KAAK,IAAI;AACb;AAiBO,IAAM,0BAA2C;AAAA,EACtD,MAAM;AAAA,EACN,aACE;AAAA,EACF,aAAa,MAAM;AAAA,EACnB,OAAO;AAAA,IACL;AAAA,MACE,MAAM;AAAA,MACN,aACE;AAAA,MACF,OAAO,iBAAiB;AAAA,MACxB,SAAS;AAAA,QACP;AAAA,QACA;AAAA,QACA;AAAA,QACA;AAAA,QACA;AAAA,QACA;AAAA,QACA;AAAA,QACA;AAAA,QACA;AAAA,QACA;AAAA,QACA;AAAA,QACA;AAAA,QACA;AAAA,QACA;AAAA,QACA;AAAA,QACA;AAAA,MACF,EAAE,KAAK,IAAI;AAAA,MACX,WAAW;AAAA,QACT,QAAQ,EAAE,SAAS,KAAK;AAAA,MAC1B;AAAA,MACA,MAAM,CAAC,UAAU;AAAA,IACnB;AAAA,EACF;AAAA,EACA,QAAQ,CAAC,uBAAuB;AAAA,EAChC,WAAW,CAAC,gCAAgC;AAAA,EAC5C,QAAQ;AAAA,IACN;AAAA,MACE,MAAM;AAAA,MACN,OAAO;AAAA,MACP,aACE;AAAA,IACJ;AAAA,IACA;AAAA,MACE,MAAM;AAAA,MACN,OAAO;AAAA,MACP,aACE;AAAA,IACJ;AAAA,IACA;AAAA,MACE,MAAM;AAAA,MACN,OAAO;AAAA,MACP,aACE;AAAA,IACJ;AAAA,IACA;AAAA,MACE,MAAM;AAAA,MACN,OAAO;AAAA,MACP,aACE;AAAA,IACJ;AAAA,EACF;AACF;;;ACriBO,IAAM,aAA8B;AAAA,EACzC,MAAM;AAAA,EACN,aAAa;AAAA,EACb,aAAa,CAAC,YAAqB,OAAO,SAAS,MAAM;AAAA,EACzD,wBAAwB,CAAC,YACvB,oBAAoB,SAAS,MAAM;AAAA,EACrC,OAAO;AAAA,IACL;AAAA,MACE,MAAM;AAAA,MACN,aAAa;AAAA,MACb,OAAO,iBAAiB;AAAA,MACxB,cAAc,CAAC,gBAAgB,cAAc;AAAA,MAC7C,SAAS;AAAA,QACP;AAAA,QACA;AAAA,QACA;AAAA,QACA;AAAA,QACA;AAAA,QACA;AAAA,QACA;AAAA,QACA;AAAA,QACA;AAAA,QACA;AAAA,QACA;AAAA,QACA;AAAA,QACA;AAAA,QACA;AAAA,QACA;AAAA,QACA;AAAA,QACA;AAAA,QACA;AAAA,QACA;AAAA,QACA;AAAA,QACA;AAAA,QACA;AAAA,QACA;AAAA,QACA;AAAA,QACA;AAAA,QACA;AAAA,QACA;AAAA,QACA;AAAA,QACA;AAAA,QACA;AAAA,QACA;AAAA,QACA;AAAA,QACA;AAAA,QACA;AAAA,QACA;AAAA,QACA;AAAA,QACA;AAAA,QACA;AAAA,QACA;AAAA,MACF,EAAE,KAAK,IAAI;AAAA,MACX,MAAM,CAAC,SAAS;AAAA,IAClB;AAAA,EACF;AAAA,EACA,mBAAmB;AAAA,IACjB,OAAO,CAAC,kBAAkB;AAAA,EAC5B;AACF;;;AC/CA,IAAM,2BAA0C;AAAA,EAC9C,MAAM;AAAA,EACN,aACE;AAAA,EACF,OAAO,YAAY;AAAA,EACnB,UAAU;AAAA,EACV,WAAW,EAAE,QAAQ,EAAE,SAAS,KAAK,EAAE;AAAA,EACvC,QAAQ;AAAA,IACN;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA,GAAG;AAAA,IACH;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;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,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA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AAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,EACF,EAAE,KAAK,IAAI;AACb;AAQA,IAAM,uBAAsC;AAAA,EAC1C,MAAM;AAAA,EACN,aACE;AAAA,EACF,OAAO,YAAY;AAAA,EACnB,UAAU;AAAA,EACV,WAAW,EAAE,QAAQ,EAAE,SAAS,KAAK,EAAE;AAAA,EACvC,QAAQ;AAAA,IACN;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA,GAAG;AAAA,IACH;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,EACF,EAAE,KAAK,IAAI;AACb;AAQA,IAAM,sBAAqC;AAAA,EACzC,MAAM;AAAA,EACN,aACE;AAAA,EACF,OAAO,YAAY;AAAA,EACnB,UAAU;AAAA,EACV,qBAAqB,CAAC;AAAA,EACtB,WAAW,EAAE,QAAQ,EAAE,SAAS,KAAK,EAAE;AAAA,EACvC,QAAQ;AAAA,IACN;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA,GAAG;AAAA,IACH;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IAC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AA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AA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;AAAA,EACN,aACE;AAAA,EACF,OAAO,YAAY;AAAA,EACnB,UAAU;AAAA,EACV,WAAW,EAAE,QAAQ,EAAE,SAAS,KAAK,EAAE;AAAA,EACvC,QAAQ;AAAA,IACN;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA,GAAG;AAAA,IACH;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AA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AAAA,QACA;AAAA,QACA;AAAA,QACA;AAAA,QACA;AAAA,QACA;AAAA,QACA;AAAA,QACA;AAAA,QACA;AAAA,QACA;AAAA,QACA;AAAA,QACA;AAAA,QACA;AAAA,QACA;AAAA,QACA;AAAA,QACA;AAAA,QACA;AAAA,QACA;AAAA,QACA;AAAA,QACA;AAAA,QACA;AAAA,QACA;AAAA,QACA;AAAA,QACA;AAAA,QACA;AAAA,QACA;AAAA,QACA;AAAA,QACA;AAAA,QACA;AAAA,QACA;AAAA,QACA;AAAA,QACA;AAAA,QACA;AAAA,QACA;AAAA,QACA;AAAA,QACA;AAAA,QACA;AAAA,QACA;AAAA,QACA;AAAA,QACA;AAAA,QACA;AAAA,QACA;AAAA,QACA;AAAA,QACA;AAAA,QACA;AAAA,QACA;AAAA,QACA;AAAA,QACA;AAAA,QACA;AAAA,QACA;AAAA,QACA;AAAA,QACA;AAAA,QACA;AAAA,QACA;AAAA,QACA;AAAA,QACA;AAAA,QACA;AAAA,QACA;AAAA,QACA;AAAA,QACA;AAAA,QACA;AAAA,QACA;AAAA,QACA;AAAA,QACA;AAAA,QACA;AAAA,QACA;AAAA,QACA;AAAA,QACA;AAAA,QACA;AAAA,QACA;AAAA,QACA;AAAA,QACA;AAAA,QACA;AAAA,QACA;AAAA,QACA;AAAA,QACA;AAAA,QACA;AAAA,QACA;AAAA,QACA;AAAA,QACA;AAAA,QACA;AAAA,QACA;AAAA,QACA;AAAA,QACA;AAAA,QACA;AAAA,QACA;AAAA,QACA;AAAA,QACA;AAAA,QACA;AAAA,QACA;AAAA,MACF,EAAE,KAAK,IAAI;AAAA,MACX,MAAM,CAAC,UAAU;AAAA,IACnB;AAAA,IACA;AAAA,MACE,MAAM;AAAA,MACN,aACE;AAAA,MACF,OAAO,iBAAiB;AAAA,MACxB,cAAc;AAAA,QACZ;AAAA,QACA;AAAA,QACA;AAAA,QACA;AAAA,QACA;AAAA,MACF;AAAA,MACA,SAAS;AAAA,QACP;AAAA,QACA;AAAA,QACA;AAAA,QACA;AAAA,QACA;AAAA,QACA;AAAA,QACA;AAAA,QACA;AAAA,QACA;AAAA,Q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IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,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IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,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AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;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","names":["Component","Component","Component","Component","Component","Component","Component","JsonFile","TextFile","TextFile","JsonFile","JsonFile","TextFile","GENERATED_MARKER","TextFile","JsonFile","path","Component","Component","TextFile","spec","import_utils","relative","Component","Component","relative","import_utils","Component","Component","Component","JsonFile","NodePackageManager","UpgradeDependenciesSchedule","merge","Component","Component","path","Component","JobPermission","JobPermission","Component","YamlFile","JobPermission","DEFAULT_WORKFLOW_NAME","NodePackageManager","UpgradeDependenciesSchedule","merge","NodePackageManager","Transform","UpgradeDependenciesSchedule","ReleaseTrigger","merge","import_utils","Component","GitHub","WorkflowSteps","JobPermission","Component","prefix","GitHub","JobPermission","WorkflowSteps","Component","GitHub","JobPermission","Component","GitHub","JobPermission","NodePackageManager","Transform","UpgradeDependenciesSchedule","ReleaseTrigger","merge","SampleFile","SampleFile","relative","Component"]}
|
|
1
|
+
{"version":3,"sources":["../../utils/src/aws/aws-types.ts","../../utils/src/git/git-utils.ts","../../utils/src/string/string-utils.ts","../../utils/src/index.ts","../src/agent/agent-config.ts","../src/agent/types.ts","../src/agent/bundles/utils.ts","../src/agent/bundles/aws-cdk.ts","../src/agent/bundles/base.ts","../src/agent/bundles/project-context.ts","../src/agent/bundles/bcm-writer.ts","../src/agent/bundles/company-profile.ts","../src/agent/bundles/github-workflow.ts","../src/agent/bundles/industry-discovery.ts","../src/agent/bundles/jest.ts","../src/agent/bundles/maintenance-audit.ts","../src/agent/bundles/meeting-analysis.ts","../src/agent/bundles/orchestrator.ts","../src/agent/bundles/people-profile.ts","../src/pnpm/pnpm-workspace.ts","../src/agent/bundles/pnpm.ts","../src/agent/bundles/pr-review.ts","../src/agent/bundles/projen.ts","../src/agent/bundles/requirements-analyst.ts","../src/agent/bundles/requirements-writer.ts","../src/agent/bundles/research-pipeline.ts","../src/projects/project-metadata.ts","../src/agent/bundles/slack.ts","../src/agent/bundles/software-profile.ts","../src/turbo/turbo-repo.ts","../src/turbo/turbo-repo-task.ts","../src/agent/bundles/turborepo.ts","../src/agent/bundles/typescript.ts","../src/vitest/vitest-component.ts","../src/versions.ts","../src/agent/bundles/vitest.ts","../src/agent/bundles/index.ts","../src/agent/bundles/scope.ts","../src/agent/renderers/claude-renderer.ts","../src/agent/renderers/codex-renderer.ts","../src/agent/renderers/copilot-renderer.ts","../src/agent/renderers/cursor-renderer.ts","../src/agent/template-resolver.ts","../src/astro/astro-config.ts","../src/astro/astro-config-options.ts","../src/aws/aws-deployment-config.ts","../src/aws/aws-deployment-target.ts","../src/latest-eligible-version.ts","../src/version-package-map.ts","../src/jsii/jsii-faker.ts","../src/projects/astro-project.ts","../src/projects/typescript-project.ts","../src/projects/monorepo-project.ts","../src/tasks/reset-task.ts","../src/vscode/vscode.ts","../src/workflows/approve-merge-upgrade.ts","../src/workflows/build-complete-job.ts","../src/workflows/sync-labels.ts","../src/projects/aws-cdk-project.ts","../src/workflows/aws-deploy-workflow.ts","../src/workflows/aws-teardown-workflow.ts","../src/projects/starlight-project.ts","../src/typescript/typescript-config.ts"],"sourcesContent":["/**\n * Stage Types\n *\n * What stage of deployment is this? Dev, staging, or prod?\n */\nexport const AWS_STAGE_TYPE = {\n /**\n * Development environment, typically used for testing and development.\n */\n DEV: \"dev\",\n\n /**\n * Staging environment, used for pre-production testing.\n */\n STAGE: \"stage\",\n\n /**\n * Production environment, used for live deployments.\n */\n PROD: \"prod\",\n} as const;\n\n/**\n * Above const as a type.\n */\nexport type AwsStageType = (typeof AWS_STAGE_TYPE)[keyof typeof AWS_STAGE_TYPE];\n\n/**\n * Deployment target role: whether an (account, region) is the primary or\n * secondary deployment target (e.g. primary vs replica region).\n */\nexport const DEPLOYMENT_TARGET_ROLE = {\n /**\n * Account and region that represents the primary region for this service.\n * For example, the base DynamoDB Region for global tables.\n */\n PRIMARY: \"primary\",\n /**\n * Account and region that represents a secondary region for this service.\n * For example, a replica region for a global DynamoDB table.\n */\n SECONDARY: \"secondary\",\n} as const;\n\n/**\n * Type for deployment target role values.\n */\nexport type DeploymentTargetRoleType =\n (typeof DEPLOYMENT_TARGET_ROLE)[keyof typeof DEPLOYMENT_TARGET_ROLE];\n\n/**\n * Environment types (primary/secondary).\n *\n * @deprecated Use {@link DEPLOYMENT_TARGET_ROLE} instead. This constant is maintained for backward compatibility.\n */\nexport const AWS_ENVIRONMENT_TYPE = DEPLOYMENT_TARGET_ROLE;\n\n/**\n * Type for environment type values.\n *\n * @deprecated Use {@link DeploymentTargetRoleType} instead. This type is maintained for backward compatibility.\n */\nexport type AwsEnvironmentType = DeploymentTargetRoleType;\n","import { execSync } from \"node:child_process\";\n\n/**\n * Returns the current full git branch name\n *\n * ie: feature/1234 returns feature/1234\n *\n */\nexport const findGitBranch = (): string => {\n return execSync(\"git rev-parse --abbrev-ref HEAD\")\n .toString(\"utf8\")\n .replace(/[\\n\\r\\s]+$/, \"\");\n};\n\nexport const findGitRepoName = (): string => {\n /**\n * When running in github actions this will be populated.\n */\n if (process.env.GITHUB_REPOSITORY) {\n return process.env.GITHUB_REPOSITORY;\n }\n\n /**\n * locally, we need to extract the repo name from the git config.\n */\n const remote = execSync(\"git config --get remote.origin.url\")\n .toString(\"utf8\")\n .replace(/[\\n\\r\\s]+$/, \"\")\n .trim();\n\n const match = remote.match(/[:\\/]([^/]+\\/[^/]+?)(?:\\.git)?$/);\n const repoName = match ? match[1] : \"error-repo-name\";\n\n return repoName;\n};\n","import * as crypto from \"node:crypto\";\n\n/**\n *\n * @param inString string to hash\n * @param trimLength trim to this length (defaults to 999 chars)\n * @returns\n */\nexport const hashString = (inString: string, trimLength: number = 999) => {\n return crypto\n .createHash(\"sha256\")\n .update(inString)\n .digest(\"hex\")\n .substring(0, trimLength);\n};\n\n/**\n *\n * @param inputString string to truncate\n * @param maxLength max length of this string\n * @returns trimmed string\n */\nexport const trimStringLength = (inputString: string, maxLength: number) => {\n return inputString.length < maxLength\n ? inputString\n : inputString.substring(0, maxLength);\n};\n","export * from \"./aws/aws-types\";\nexport * from \"./git/git-utils\";\nexport * from \"./string/string-utils\";\n","import { Component, Project } from \"projen\";\nimport {\n AgentConfigOptions,\n AgentRuleBundle,\n ClaudeSettingsConfig,\n} from \"./agent-config-options\";\nimport { BUILT_IN_BUNDLES } from \"./bundles\";\nimport { scopeFilePatternsToProjects } from \"./bundles/scope\";\nimport { ProjectMetadata } from \"../projects/project-metadata\";\nimport { ResolvedProjectMetadata } from \"../projects/project-metadata-options\";\nimport { ClaudeRenderer } from \"./renderers/claude-renderer\";\nimport { CodexRenderer } from \"./renderers/codex-renderer\";\nimport { CopilotRenderer } from \"./renderers/copilot-renderer\";\nimport { CursorRenderer } from \"./renderers/cursor-renderer\";\nimport { resolveTemplateVariables } from \"./template-resolver\";\nimport {\n AGENT_PLATFORM,\n AGENT_RULE_SCOPE,\n AgentPlatform,\n AgentProcedure,\n AgentRule,\n AgentSkill,\n AgentSubAgent,\n} from \"./types\";\n\n/*******************************************************************************\n *\n * Default Claude Code permissions — hardened baseline that minimises approval\n * prompts while blocking destructive and dangerous operations.\n *\n * Projects can extend these via `claudeSettings.permissions.allow` /\n * `.deny` — user-supplied entries are appended (not replaced).\n *\n ******************************************************************************/\n\n/** @internal */\nconst DEFAULT_CLAUDE_ALLOW: ReadonlyArray<string> = [\n // ── Git ──────────────────────────────────────────────────────────────\n \"Bash(git add *)\",\n \"Bash(git branch *)\",\n \"Bash(git checkout *)\",\n \"Bash(git commit *)\",\n \"Bash(git diff *)\",\n \"Bash(git fetch *)\",\n \"Bash(git log *)\",\n \"Bash(git merge *)\",\n \"Bash(git mv *)\",\n \"Bash(git pull *)\",\n \"Bash(git push *)\",\n \"Bash(git rebase *)\",\n \"Bash(git rm *)\",\n \"Bash(git stash *)\",\n \"Bash(git status *)\",\n \"Bash(git show *)\",\n \"Bash(git rev-parse *)\",\n\n // ── GitHub CLI ───────────────────────────────────────────────────────\n \"Bash(gh issue *)\",\n \"Bash(gh pr *)\",\n \"Bash(gh repo *)\",\n \"Bash(gh api *)\",\n \"Bash(gh label *)\",\n \"Bash(gh run *)\",\n \"Bash(gh search *)\",\n \"Bash(gh browse *)\",\n \"Bash(gh status *)\",\n\n // ── Package manager ──────────────────────────────────────────────────\n \"Bash(pnpm *)\",\n\n // ── Read-only shell utilities ────────────────────────────────────────\n \"Bash(ls *)\",\n \"Bash(find *)\",\n \"Bash(cat *)\",\n \"Bash(head *)\",\n \"Bash(tail *)\",\n \"Bash(wc *)\",\n \"Bash(grep *)\",\n \"Bash(sort *)\",\n \"Bash(uniq *)\",\n \"Bash(dirname *)\",\n \"Bash(basename *)\",\n \"Bash(which *)\",\n \"Bash(diff *)\",\n \"Bash(jq *)\",\n \"Bash(date *)\",\n\n // ── Safe output / test utilities ─────────────────────────────────────\n \"Bash(echo *)\",\n \"Bash(printf *)\",\n \"Bash(test *)\",\n \"Bash([ *)\",\n \"Bash(true *)\",\n \"Bash(false *)\",\n\n // ── Safe directory operations ────────────────────────────────────────\n \"Bash(mkdir *)\",\n \"Bash(rmdir *)\",\n\n // ── Built-in tools ───────────────────────────────────────────────────\n \"Read(/**)\",\n \"Edit(/**)\",\n \"Write(/**)\",\n \"WebFetch\",\n \"WebSearch\",\n];\n\n/** @internal */\nconst DEFAULT_CLAUDE_DENY: ReadonlyArray<string> = [\n // ── Destructive git ──────────────────────────────────────────────────\n \"Bash(git push --force *)\",\n \"Bash(git push -f *)\",\n \"Bash(git push origin --force *)\",\n \"Bash(git push origin -f *)\",\n \"Bash(git reset --hard *)\",\n \"Bash(git clean -f *)\",\n \"Bash(git remote *)\",\n\n // ── Destructive file operations ──────────────────────────────────────\n \"Bash(rm -rf *)\",\n \"Bash(rm -r *)\",\n \"Bash(rm *)\",\n\n // ── Network / remote access ──────────────────────────────────────────\n \"Bash(curl *)\",\n \"Bash(wget *)\",\n \"Bash(ssh *)\",\n \"Bash(scp *)\",\n\n // ── System administration ────────────────────────────────────────────\n \"Bash(sudo *)\",\n \"Bash(chmod *)\",\n \"Bash(chown *)\",\n \"Bash(kill *)\",\n \"Bash(killall *)\",\n \"Bash(pkill *)\",\n\n // ── Code execution / shell spawning ──────────────────────────────────\n \"Bash(eval *)\",\n \"Bash(exec *)\",\n \"Bash(source *)\",\n \"Bash(. *)\",\n \"Bash(bash *)\",\n \"Bash(sh *)\",\n \"Bash(zsh *)\",\n\n // ── App launching ────────────────────────────────────────────────────\n \"Bash(open *)\",\n \"Bash(xdg-open *)\",\n\n // ── Environment manipulation ─────────────────────────────────────────\n \"Bash(export *)\",\n \"Bash(env *)\",\n];\n\n/**\n * Generates AI coding assistant configuration files from a common schema.\n *\n * Supports Cursor and Claude Code (initial release), with Codex and Copilot\n * renderers planned for future issues. Rules, skills, and sub-agents are\n * defined once and rendered into the correct format for each target platform.\n *\n * Follows the configulator component pattern: extends Component, static .of()\n * factory, options interface with JSDoc.\n *\n * @example\n * ```ts\n * new AgentConfig(project, {\n * rules: [{\n * name: 'my-rule',\n * description: 'Project conventions',\n * scope: AGENT_RULE_SCOPE.ALWAYS,\n * content: '# My Rule\\n\\nFollow these conventions...',\n * }],\n * });\n * ```\n */\nexport class AgentConfig extends Component {\n /**\n * Find the AgentConfig component on a project.\n */\n public static of(project: Project): AgentConfig | undefined {\n const isAgentConfig = (c: Component): c is AgentConfig =>\n c instanceof AgentConfig;\n return project.components.find(isAgentConfig);\n }\n\n /**\n * Merges default Claude permissions with bundle and user-supplied settings.\n *\n * Merge order: defaults → bundle permissions → user-supplied entries.\n * `defaultMode` defaults to `\"dontAsk\"` unless overridden.\n */\n private static mergeClaudeDefaults(\n userSettings?: ClaudeSettingsConfig,\n bundlePermissions?: { allow: Array<string>; deny: Array<string> },\n ): ClaudeSettingsConfig {\n const bundleAllow = bundlePermissions?.allow ?? [];\n const bundleDeny = bundlePermissions?.deny ?? [];\n const userAllow = userSettings?.permissions?.allow ?? [];\n const userDeny = userSettings?.permissions?.deny ?? [];\n\n return {\n ...userSettings,\n defaultMode: userSettings?.defaultMode ?? \"dontAsk\",\n permissions: {\n ...userSettings?.permissions,\n allow: [...DEFAULT_CLAUDE_ALLOW, ...bundleAllow, ...userAllow],\n deny: [...DEFAULT_CLAUDE_DENY, ...bundleDeny, ...userDeny],\n },\n };\n }\n\n private readonly options: AgentConfigOptions;\n\n constructor(project: Project, options: AgentConfigOptions = {}) {\n super(project);\n this.options = options;\n }\n\n /**\n * Returns the bundles that are active for this project: auto-detected\n * bundles (when `autoDetectBundles !== false`) plus force-included\n * bundles, minus explicitly excluded bundles. Deduplicated by name.\n *\n * Exposed so sibling components (e.g. the sync-labels workflow) can\n * consume bundle-contributed configuration.\n */\n public get activeBundles(): ReadonlyArray<AgentRuleBundle> {\n const bundleMap = new Map<string, AgentRuleBundle>();\n\n if (this.options.autoDetectBundles !== false) {\n for (const bundle of BUILT_IN_BUNDLES) {\n if (this.options.excludeBundles?.includes(bundle.name)) {\n continue;\n }\n if (bundle.name === \"base\" && this.options.includeBaseRules === false) {\n continue;\n }\n if (bundle.appliesWhen(this.project)) {\n bundleMap.set(bundle.name, bundle);\n }\n }\n }\n\n if (this.options.includeBundles) {\n for (const bundleName of this.options.includeBundles) {\n const bundle = BUILT_IN_BUNDLES.find((b) => b.name === bundleName);\n if (bundle) {\n bundleMap.set(bundle.name, bundle);\n }\n }\n }\n\n return [...bundleMap.values()];\n }\n\n public override preSynthesize(): void {\n super.preSynthesize();\n\n const platforms = this.resolvePlatforms();\n const rules = this.resolveRules();\n const skills = this.resolveSkills();\n const subAgents = this.resolveSubAgents();\n const procedures = this.resolveProcedures();\n const mcpServers = this.options.mcpServers ?? {};\n\n // Resolve template variables in rule content, skill instructions, and\n // sub-agent prompts using ProjectMetadata (if available).\n const projectMetadata = ProjectMetadata.of(this.project);\n const metadata = projectMetadata?.metadata;\n const resolvedRules = this.resolveTemplates(rules, metadata);\n const resolvedSkills = this.resolveSkillTemplates(skills, metadata);\n const resolvedSubAgents = this.resolveSubAgentTemplates(\n subAgents,\n metadata,\n );\n const resolvedProcedures = this.resolveProcedureTemplates(\n procedures,\n metadata,\n );\n\n if (platforms.includes(AGENT_PLATFORM.CURSOR)) {\n CursorRenderer.render(\n this,\n resolvedRules,\n resolvedSkills,\n resolvedSubAgents,\n mcpServers,\n this.options.cursorSettings,\n );\n }\n\n if (platforms.includes(AGENT_PLATFORM.CLAUDE)) {\n const bundlePermissions = this.resolveBundlePermissions();\n ClaudeRenderer.render(\n this,\n resolvedRules,\n resolvedSkills,\n resolvedSubAgents,\n mcpServers,\n AgentConfig.mergeClaudeDefaults(\n this.options.claudeSettings,\n bundlePermissions,\n ),\n resolvedProcedures,\n );\n }\n\n if (platforms.includes(AGENT_PLATFORM.CODEX)) {\n CodexRenderer.render(\n this,\n resolvedRules,\n resolvedSkills,\n resolvedSubAgents,\n );\n }\n\n if (platforms.includes(AGENT_PLATFORM.COPILOT)) {\n CopilotRenderer.render(\n this,\n resolvedRules,\n resolvedSkills,\n resolvedSubAgents,\n );\n }\n }\n\n private resolvePlatforms(): ReadonlyArray<AgentPlatform> {\n return (\n this.options.platforms ?? [AGENT_PLATFORM.CURSOR, AGENT_PLATFORM.CLAUDE]\n );\n }\n\n private resolveRules(): AgentRule[] {\n const ruleMap = new Map<string, AgentRule>();\n\n // 1. Auto-detected bundle rules\n if (this.options.autoDetectBundles !== false) {\n for (const bundle of BUILT_IN_BUNDLES) {\n if (this.options.excludeBundles?.includes(bundle.name)) continue;\n if (bundle.name === \"base\" && this.options.includeBaseRules === false) {\n continue;\n }\n if (bundle.appliesWhen(this.project)) {\n for (const rule of this.bundleRulesFor(bundle)) {\n ruleMap.set(rule.name, rule);\n }\n }\n }\n }\n\n // 2. Force-included bundles\n if (this.options.includeBundles) {\n for (const bundleName of this.options.includeBundles) {\n const bundle = BUILT_IN_BUNDLES.find((b) => b.name === bundleName);\n if (bundle) {\n for (const rule of this.bundleRulesFor(bundle)) {\n ruleMap.set(rule.name, rule);\n }\n }\n }\n }\n\n // 3. Custom rules (override bundle rules with same name)\n if (this.options.rules) {\n for (const rule of this.options.rules) {\n ruleMap.set(rule.name, rule);\n }\n }\n\n // 4. Remove excluded rules\n if (this.options.excludeRules) {\n for (const name of this.options.excludeRules) {\n ruleMap.delete(name);\n }\n }\n\n // 5. Apply rule extensions (append content to existing rules)\n if (this.options.ruleExtensions) {\n for (const [name, extra] of Object.entries(this.options.ruleExtensions)) {\n const existing = ruleMap.get(name);\n if (existing) {\n ruleMap.set(name, {\n ...existing,\n content: `${existing.content}\\n\\n---\\n\\n${extra}`,\n });\n }\n }\n }\n\n // 6. Sort: project-overview first, then by first tag (alphabetical), then by name\n return [...ruleMap.values()].sort((a, b) => {\n if (a.name === \"project-overview\") return -1;\n if (b.name === \"project-overview\") return 1;\n\n const tagA = a.tags?.[0] ?? \"\\uffff\";\n const tagB = b.tags?.[0] ?? \"\\uffff\";\n if (tagA !== tagB) return tagA.localeCompare(tagB);\n\n return a.name.localeCompare(b.name);\n });\n }\n\n /**\n * Return a bundle's rules with `filePatterns` narrowed to the projects\n * that actually matched the bundle's detection predicate (when the bundle\n * provides `findApplicableProjects`). Rules with `ALWAYS` scope and rules\n * on bundles that don't implement the hook are returned unchanged.\n */\n private bundleRulesFor(bundle: AgentRuleBundle): ReadonlyArray<AgentRule> {\n if (!bundle.findApplicableProjects) {\n return bundle.rules;\n }\n const detected = bundle.findApplicableProjects(this.project);\n if (detected.length === 0) {\n return bundle.rules;\n }\n const scoped = scopeFilePatternsToProjects(this.project, detected);\n return bundle.rules.map((rule) =>\n rule.scope === AGENT_RULE_SCOPE.FILE_PATTERN\n ? { ...rule, filePatterns: scoped }\n : rule,\n );\n }\n\n private resolveSkills(): AgentSkill[] {\n const skillMap = new Map<string, AgentSkill>();\n\n // 1. Auto-detected bundle skills\n if (this.options.autoDetectBundles !== false) {\n for (const bundle of BUILT_IN_BUNDLES) {\n if (this.options.excludeBundles?.includes(bundle.name)) continue;\n if (bundle.appliesWhen(this.project) && bundle.skills) {\n for (const skill of bundle.skills) {\n skillMap.set(skill.name, skill);\n }\n }\n }\n }\n\n // 2. Force-included bundle skills\n if (this.options.includeBundles) {\n for (const bundleName of this.options.includeBundles) {\n const bundle = BUILT_IN_BUNDLES.find((b) => b.name === bundleName);\n if (bundle?.skills) {\n for (const skill of bundle.skills) {\n skillMap.set(skill.name, skill);\n }\n }\n }\n }\n\n // 3. Custom skills (override)\n if (this.options.skills) {\n for (const skill of this.options.skills) {\n skillMap.set(skill.name, skill);\n }\n }\n\n return [...skillMap.values()];\n }\n\n private resolveSubAgents(): AgentSubAgent[] {\n const agentMap = new Map<string, AgentSubAgent>();\n\n // 1. Auto-detected bundle sub-agents\n if (this.options.autoDetectBundles !== false) {\n for (const bundle of BUILT_IN_BUNDLES) {\n if (this.options.excludeBundles?.includes(bundle.name)) continue;\n if (bundle.appliesWhen(this.project) && bundle.subAgents) {\n for (const agent of bundle.subAgents) {\n agentMap.set(agent.name, agent);\n }\n }\n }\n }\n\n // 2. Force-included bundle sub-agents\n if (this.options.includeBundles) {\n for (const bundleName of this.options.includeBundles) {\n const bundle = BUILT_IN_BUNDLES.find((b) => b.name === bundleName);\n if (bundle?.subAgents) {\n for (const agent of bundle.subAgents) {\n agentMap.set(agent.name, agent);\n }\n }\n }\n }\n\n // 3. Custom sub-agents (override)\n if (this.options.subAgents) {\n for (const agent of this.options.subAgents) {\n agentMap.set(agent.name, agent);\n }\n }\n\n return [...agentMap.values()];\n }\n\n private resolveProcedures(): AgentProcedure[] {\n const procMap = new Map<string, AgentProcedure>();\n\n // 1. Auto-detected bundle procedures\n if (this.options.autoDetectBundles !== false) {\n for (const bundle of BUILT_IN_BUNDLES) {\n if (this.options.excludeBundles?.includes(bundle.name)) continue;\n if (bundle.appliesWhen(this.project) && bundle.procedures) {\n for (const proc of bundle.procedures) {\n procMap.set(proc.name, proc);\n }\n }\n }\n }\n\n // 2. Force-included bundle procedures\n if (this.options.includeBundles) {\n for (const bundleName of this.options.includeBundles) {\n const bundle = BUILT_IN_BUNDLES.find((b) => b.name === bundleName);\n if (bundle?.procedures) {\n for (const proc of bundle.procedures) {\n procMap.set(proc.name, proc);\n }\n }\n }\n }\n\n // 3. Custom procedures (override)\n if (this.options.procedures) {\n for (const proc of this.options.procedures) {\n procMap.set(proc.name, proc);\n }\n }\n\n return [...procMap.values()];\n }\n\n /**\n * Resolves template variables in rule content using project metadata.\n * Emits synthesis warnings for rules with unresolved variables.\n */\n private resolveTemplates(\n rules: ReadonlyArray<AgentRule>,\n metadata: ResolvedProjectMetadata | undefined,\n ): ReadonlyArray<AgentRule> {\n return rules.map((rule) => {\n const { resolved, unresolvedKeys } = resolveTemplateVariables(\n rule.content,\n metadata,\n );\n if (unresolvedKeys.length > 0) {\n this.project.logger.warn(\n `AgentConfig: ProjectMetadata not found; rule '${rule.name}' using default values`,\n );\n }\n return resolved !== rule.content ? { ...rule, content: resolved } : rule;\n });\n }\n\n /**\n * Resolves template variables in skill instructions using project metadata.\n */\n private resolveSkillTemplates(\n skills: ReadonlyArray<AgentSkill>,\n metadata: ResolvedProjectMetadata | undefined,\n ): ReadonlyArray<AgentSkill> {\n return skills.map((skill) => {\n const { resolved, unresolvedKeys } = resolveTemplateVariables(\n skill.instructions,\n metadata,\n );\n if (unresolvedKeys.length > 0) {\n this.project.logger.warn(\n `AgentConfig: ProjectMetadata not found; skill '${skill.name}' using default values`,\n );\n }\n return resolved !== skill.instructions\n ? { ...skill, instructions: resolved }\n : skill;\n });\n }\n\n /**\n * Resolves template variables in sub-agent prompts using project metadata.\n */\n private resolveSubAgentTemplates(\n subAgents: ReadonlyArray<AgentSubAgent>,\n metadata: ResolvedProjectMetadata | undefined,\n ): ReadonlyArray<AgentSubAgent> {\n return subAgents.map((agent) => {\n const { resolved, unresolvedKeys } = resolveTemplateVariables(\n agent.prompt,\n metadata,\n );\n if (unresolvedKeys.length > 0) {\n this.project.logger.warn(\n `AgentConfig: ProjectMetadata not found; sub-agent '${agent.name}' using default values`,\n );\n }\n return resolved !== agent.prompt ? { ...agent, prompt: resolved } : agent;\n });\n }\n\n /**\n * Resolves template variables in procedure content using project metadata.\n */\n private resolveProcedureTemplates(\n procedures: ReadonlyArray<AgentProcedure>,\n metadata: ResolvedProjectMetadata | undefined,\n ): ReadonlyArray<AgentProcedure> {\n return procedures.map((proc) => {\n const { resolved, unresolvedKeys } = resolveTemplateVariables(\n proc.content,\n metadata,\n );\n if (unresolvedKeys.length > 0) {\n this.project.logger.warn(\n `AgentConfig: ProjectMetadata not found; procedure '${proc.name}' using default values`,\n );\n }\n return resolved !== proc.content ? { ...proc, content: resolved } : proc;\n });\n }\n\n /**\n * Collects Claude permission entries from all active bundles.\n */\n private resolveBundlePermissions(): {\n allow: Array<string>;\n deny: Array<string>;\n } {\n const allow: Array<string> = [];\n const deny: Array<string> = [];\n\n if (this.options.autoDetectBundles !== false) {\n for (const bundle of BUILT_IN_BUNDLES) {\n if (this.options.excludeBundles?.includes(bundle.name)) continue;\n if (bundle.appliesWhen(this.project) && bundle.claudePermissions) {\n if (bundle.claudePermissions.allow) {\n allow.push(...bundle.claudePermissions.allow);\n }\n if (bundle.claudePermissions.deny) {\n deny.push(...bundle.claudePermissions.deny);\n }\n }\n }\n }\n\n // Force-included bundles\n if (this.options.includeBundles) {\n for (const bundleName of this.options.includeBundles) {\n const bundle = BUILT_IN_BUNDLES.find((b) => b.name === bundleName);\n if (bundle?.claudePermissions) {\n if (bundle.claudePermissions.allow) {\n allow.push(...bundle.claudePermissions.allow);\n }\n if (bundle.claudePermissions.deny) {\n deny.push(...bundle.claudePermissions.deny);\n }\n }\n }\n }\n\n return { allow, deny };\n }\n}\n","/**\n * Defines the scope/activation model for an agent rule.\n * - ALWAYS: Rule is always active regardless of context\n * - FILE_PATTERN: Rule activates when the AI is working on files matching the patterns\n */\nexport const AGENT_RULE_SCOPE = {\n ALWAYS: \"always\",\n FILE_PATTERN: \"file-pattern\",\n} as const;\n\nexport type AgentRuleScope =\n (typeof AGENT_RULE_SCOPE)[keyof typeof AGENT_RULE_SCOPE];\n\n/**\n * Supported AI coding assistant platforms.\n */\nexport const AGENT_PLATFORM = {\n CURSOR: \"cursor\",\n CLAUDE: \"claude\",\n CODEX: \"codex\",\n COPILOT: \"copilot\",\n} as const;\n\nexport type AgentPlatform =\n (typeof AGENT_PLATFORM)[keyof typeof AGENT_PLATFORM];\n\n/**\n * Render target for Claude Code rules.\n * - SCOPED_FILE: .claude/rules/{name}.md (default — supports paths frontmatter for conditional activation)\n * - AGENTS_MD: AGENTS.md (always-active, shared with Codex)\n * - CLAUDE_MD: CLAUDE.md (always-active, Claude-only content not consumed by other agents)\n */\nexport const CLAUDE_RULE_TARGET = {\n SCOPED_FILE: \"scoped-file\",\n AGENTS_MD: \"agents-md\",\n CLAUDE_MD: \"claude-md\",\n} as const;\n\nexport type ClaudeRuleTarget =\n (typeof CLAUDE_RULE_TARGET)[keyof typeof CLAUDE_RULE_TARGET];\n\n/**\n * Model selection for sub-agents. Platforms map these to their own model identifiers.\n */\nexport const AGENT_MODEL = {\n INHERIT: \"inherit\",\n FAST: \"fast\",\n BALANCED: \"balanced\",\n POWERFUL: \"powerful\",\n} as const;\n\nexport type AgentModel = (typeof AGENT_MODEL)[keyof typeof AGENT_MODEL];\n\n/**\n * Maps abstract AGENT_MODEL values to Claude Code model aliases.\n * Returns undefined for \"inherit\" (omit the field entirely).\n * Cursor omits the model field to use its default model selection.\n */\nexport function resolveModelAlias(\n model: string | undefined,\n): string | undefined {\n if (!model || model === AGENT_MODEL.INHERIT) {\n return undefined;\n }\n const mapping: Record<string, string> = {\n [AGENT_MODEL.POWERFUL]: \"opus\",\n [AGENT_MODEL.BALANCED]: \"sonnet\",\n [AGENT_MODEL.FAST]: \"haiku\",\n };\n return mapping[model] ?? model;\n}\n\n/**\n * MCP server transport type.\n */\nexport const MCP_TRANSPORT = {\n STDIO: \"stdio\",\n HTTP: \"http\",\n SSE: \"sse\",\n} as const;\n\nexport type McpTransport = (typeof MCP_TRANSPORT)[keyof typeof MCP_TRANSPORT];\n\n/**\n * Platform-specific overrides for a rule.\n */\nexport interface AgentPlatformOverrides {\n /** Cursor-specific overrides */\n readonly cursor?: {\n /** Override the description used in Cursor's YAML frontmatter */\n readonly description?: string;\n /** Exclude this rule from Cursor output entirely */\n readonly exclude?: boolean;\n };\n /** Claude Code-specific overrides */\n readonly claude?: {\n /**\n * Where to render this rule for Claude Code.\n * - SCOPED_FILE: .claude/rules/{name}.md (default — supports paths frontmatter)\n * - AGENTS_MD: AGENTS.md (always-active, shared with Codex)\n * - CLAUDE_MD: CLAUDE.md (always-active, Claude-only)\n */\n readonly target?: ClaudeRuleTarget;\n /** Exclude this rule from Claude Code output entirely */\n readonly exclude?: boolean;\n };\n /** Codex-specific overrides (future) */\n readonly codex?: {\n /** Place this rule in a sub-directory AGENTS.md instead of root */\n readonly directory?: string;\n /** Exclude this rule from Codex output entirely */\n readonly exclude?: boolean;\n };\n /** Copilot-specific overrides (future) */\n readonly copilot?: {\n /** Exclude this rule from Copilot output entirely */\n readonly exclude?: boolean;\n };\n}\n\n/**\n * A single agent rule definition, platform-agnostic.\n */\nexport interface AgentRule {\n /**\n * Unique identifier for the rule. Used as the filename stem in platforms\n * that use per-rule files (Cursor, Claude Code, Copilot).\n * @example 'typescript-conventions'\n */\n readonly name: string;\n\n /**\n * Human-readable description of the rule's purpose.\n * Used by Cursor for AI-assisted rule selection.\n * @example 'TypeScript project patterns and conventions'\n */\n readonly description: string;\n\n /**\n * Activation scope for this rule.\n * - AGENT_RULE_SCOPE.ALWAYS: Active in all contexts\n * - AGENT_RULE_SCOPE.FILE_PATTERN: Active only when working on matching files\n */\n readonly scope: AgentRuleScope;\n\n /**\n * Glob patterns for conditional activation.\n * Required when scope is AGENT_RULE_SCOPE.FILE_PATTERN.\n * @example ['src/**\\/*.ts', 'tests/**\\/*.ts']\n */\n readonly filePatterns?: ReadonlyArray<string>;\n\n /**\n * The rule content as markdown. This is the platform-agnostic body\n * that applies equally to all AI assistants.\n */\n readonly content: string;\n\n /**\n * Optional per-platform overrides. Use sparingly — prefer platform-agnostic content.\n */\n readonly platforms?: AgentPlatformOverrides;\n\n /**\n * Optional tags for categorizing and ordering rules.\n * Rules are ordered by tag (alphabetical), then by name within each tag.\n * @example ['typescript', 'testing', 'workflow']\n */\n readonly tags?: ReadonlyArray<string>;\n}\n\n/**\n * A skill definition following the cross-platform Agent Skills specification.\n * Rendered to .claude/skills/ (Claude Code) and .cursor/skills/ (Cursor).\n */\nexport interface AgentSkill {\n /**\n * Unique identifier for the skill. Becomes the /slash-command name.\n * @example 'commit'\n */\n readonly name: string;\n\n /**\n * Human-readable description. Claude uses this to decide when to auto-invoke.\n */\n readonly description: string;\n\n /**\n * Multi-line instruction content (markdown). Becomes the SKILL.md body.\n */\n readonly instructions: string;\n\n /**\n * Optional tool allowlist for this skill.\n * @example ['Read', 'Bash(npm run *)']\n */\n readonly allowedTools?: ReadonlyArray<string>;\n\n /**\n * Whether to prevent auto-invocation of this skill.\n * When true, only triggered by the user typing /skill-name.\n * @default false\n */\n readonly disableModelInvocation?: boolean;\n\n /**\n * Whether the user can invoke this skill directly via /skill-name.\n * Set to false for background skills that should not appear in the / menu.\n * @default true\n */\n readonly userInvocable?: boolean;\n\n /**\n * Model override when this skill is active.\n * @example 'claude-opus-4-6'\n */\n readonly model?: string;\n\n /**\n * Reasoning effort level when this skill is active.\n * @example 'high'\n */\n readonly effort?: string;\n\n /**\n * Glob patterns that limit when the skill is auto-loaded.\n * @example ['src/api/**\\/*.ts']\n */\n readonly paths?: ReadonlyArray<string>;\n\n /**\n * Resource directories bundled with the skill (e.g., references/, scripts/, assets/).\n * Documentation hint only — directory names listed here are not emitted to disk.\n * Prefer {@link referenceFiles} to ship actual companion file contents.\n *\n * @deprecated Use {@link referenceFiles} to emit physical companion files.\n * @example ['references/', 'scripts/']\n */\n readonly references?: ReadonlyArray<string>;\n\n /**\n * Companion files shipped alongside the SKILL.md (e.g., templates, references, scripts).\n * Each entry is rendered as a TextFile under the skill's directory on every\n * platform that emits skills (Claude: `.claude/skills/{name}/{path}`,\n * Cursor: `.cursor/skills/{name}/{path}`).\n *\n * Use this for skill assets that benefit from being separate files rather than\n * inlined into the skill instructions — large templates, reference tables,\n * runnable scripts.\n *\n * Per-platform `platforms.{claude,cursor}.exclude` flags suppress reference\n * files for that platform alongside the SKILL.md.\n *\n * @example\n * referenceFiles: [\n * { path: '_references/templates/_template-FR.md', content: '# Functional Requirement\\n...' },\n * { path: '_references/standards-and-frameworks.md', content: '# Standards\\n...' },\n * ]\n */\n readonly referenceFiles?: ReadonlyArray<{\n /** Path relative to the skill directory (e.g., `_references/templates/_template-FR.md`). */\n readonly path: string;\n /** File contents written verbatim. */\n readonly content: string;\n }>;\n\n /**\n * Context isolation mode. Set to 'fork' to run in an isolated subagent context.\n */\n readonly context?: string;\n\n /**\n * Subagent name to delegate to when context is 'fork'.\n * @example 'code-reviewer'\n */\n readonly agent?: string;\n\n /**\n * Shell for dynamic context injection via !`command` syntax.\n * @default 'bash'\n */\n readonly shell?: string;\n\n /** Per-platform overrides. Use `exclude: true` to skip a platform. */\n readonly platforms?: {\n readonly claude?: { readonly exclude?: boolean };\n readonly cursor?: { readonly exclude?: boolean };\n };\n}\n\n/**\n * Platform-specific overrides for a sub-agent definition.\n */\n/**\n * Copilot handoff definition for sub-agent delegation.\n */\nexport interface CopilotHandoff {\n /** Display label for the handoff action. */\n readonly label: string;\n /** Target agent name. */\n readonly agent: string;\n /** Optional prompt to pass to the target agent. */\n readonly prompt?: string;\n /** Whether to auto-send the handoff without user confirmation. */\n readonly send?: boolean;\n}\n\nexport interface AgentSubAgentPlatformOverrides {\n /** Claude Code-specific overrides */\n readonly claude?: {\n /** Permission mode: default, acceptEdits, dontAsk, bypassPermissions, plan */\n readonly permissionMode?: string;\n /** Run in isolated git worktree */\n readonly isolation?: string;\n /** Run as a background task */\n readonly background?: boolean;\n /** Reasoning effort level (Opus): low, medium, high, max */\n readonly effort?: string;\n /** Persistent memory scope: user, project, local */\n readonly memory?: string;\n /** Exclude this sub-agent from Claude Code output entirely */\n readonly exclude?: boolean;\n };\n /** Cursor-specific overrides */\n readonly cursor?: {\n /** Restrict the sub-agent to read-only operations */\n readonly readonly?: boolean;\n /** Run the sub-agent asynchronously as a background task */\n readonly isBackground?: boolean;\n /** Exclude this sub-agent from Cursor output entirely */\n readonly exclude?: boolean;\n };\n /** Codex-specific overrides (future) */\n readonly codex?: {\n /** Sandbox mode: read-only or full */\n readonly sandboxMode?: string;\n /** Model reasoning effort */\n readonly modelReasoningEffort?: string;\n /** Exclude this sub-agent from Codex output entirely */\n readonly exclude?: boolean;\n };\n /** Copilot-specific overrides (future) */\n readonly copilot?: {\n /** Target environment: vscode or github-copilot */\n readonly target?: string;\n /** Whether the user can invoke this sub-agent directly */\n readonly userInvocable?: boolean;\n /** Prevent auto-invocation of this sub-agent */\n readonly disableModelInvocation?: boolean;\n /** Handoff definitions for agent-to-agent delegation */\n readonly handoffs?: ReadonlyArray<CopilotHandoff>;\n /** Exclude this sub-agent from Copilot output entirely */\n readonly exclude?: boolean;\n };\n}\n\n/**\n * A custom sub-agent definition, platform-agnostic.\n * Rendered to .cursor/agents/ (Cursor), .claude/agents/ (Claude Code).\n */\nexport interface AgentSubAgent {\n /**\n * Unique identifier for the sub-agent. Used as the filename stem.\n * Must be lowercase letters and hyphens only.\n * @example 'code-reviewer'\n */\n readonly name: string;\n\n /** Human-readable description. Used by the parent agent to decide when to delegate. */\n readonly description: string;\n\n /**\n * System prompt / instructions for the sub-agent (markdown).\n * This becomes the body of the generated agent file.\n */\n readonly prompt: string;\n\n /**\n * Model selection for this sub-agent.\n * @default AGENT_MODEL.INHERIT\n */\n readonly model?: AgentModel;\n\n /**\n * Tool allowlist. When omitted, inherits all tools from parent.\n * @example ['Read', 'Glob', 'Grep']\n */\n readonly tools?: ReadonlyArray<string>;\n\n /**\n * Tool denylist. Applied before the allowlist.\n * @example ['Bash', 'Write']\n */\n readonly disallowedTools?: ReadonlyArray<string>;\n\n /** Maximum agentic turns before the sub-agent stops. */\n readonly maxTurns?: number;\n\n /**\n * Skills to preload for this sub-agent.\n * @example ['commit', 'review-pr']\n */\n readonly skills?: ReadonlyArray<string>;\n\n /**\n * MCP servers available to this sub-agent.\n * Rendered to the platform-specific sub-agent config.\n */\n readonly mcpServers?: Readonly<Record<string, McpServerConfig>>;\n\n /**\n * Sub-agents this agent can invoke/delegate to.\n * @example ['test-writer', 'code-reviewer']\n */\n readonly canDelegateToAgents?: ReadonlyArray<string>;\n\n /** Optional per-platform overrides for this sub-agent. */\n readonly platforms?: AgentSubAgentPlatformOverrides;\n}\n\n/**\n * An executable procedure (shell script) that ships with a bundle.\n * Rendered to .claude/procedures/{name} as an executable file.\n */\nexport interface AgentProcedure {\n /**\n * Filename for the procedure (e.g., 'check-blocked.sh').\n * Used as the filename in .claude/procedures/.\n */\n readonly name: string;\n\n /** Human-readable description of what this procedure does. */\n readonly description: string;\n\n /** Script content as a single string. Lines are split on newlines for rendering. */\n readonly content: string;\n}\n\n/**\n * MCP server configuration. Cross-platform — rendered to .claude/settings.json\n * (Claude Code) and .cursor/mcp.json (Cursor).\n */\nexport interface McpServerConfig {\n /**\n * Transport type for the server connection.\n * @default MCP_TRANSPORT.STDIO\n */\n readonly transport?: McpTransport;\n\n /** Command to launch a stdio server. */\n readonly command?: string;\n\n /** Command arguments for stdio server. */\n readonly args?: ReadonlyArray<string>;\n\n /** URL for HTTP/SSE remote servers. */\n readonly url?: string;\n\n /** HTTP headers for HTTP/SSE connections. */\n readonly headers?: Readonly<Record<string, string>>;\n\n /** Environment variables for the server process. */\n readonly env?: Readonly<Record<string, string>>;\n\n /**\n * Tool allowlist — only these tools from the server will be available.\n * @example ['read_file', 'search']\n */\n readonly enabledTools?: ReadonlyArray<string>;\n\n /**\n * Tool denylist — these tools from the server will be blocked.\n * Applied before enabledTools.\n * @example ['delete_file', 'execute']\n */\n readonly disabledTools?: ReadonlyArray<string>;\n}\n","import { Component, Project } from \"projen/lib\";\n\n/**\n * Return the project and/or subprojects that have a component of a given type.\n * Walks one level of subprojects (does not recurse into sub-subprojects).\n */\nexport function findProjectsWithComponent<T extends Component>(\n project: Project,\n ctor: new (...args: any[]) => T,\n): Array<Project> {\n const out: Array<Project> = [];\n if (project.components.some((c) => c instanceof ctor)) {\n out.push(project);\n }\n for (const sub of project.subprojects) {\n if (sub.components.some((c) => c instanceof ctor)) {\n out.push(sub);\n }\n }\n return out;\n}\n\n/**\n * Return the project and/or subprojects that declare a dependency with the\n * given name. Walks one level of subprojects.\n */\nexport function findProjectsWithDep(\n project: Project,\n name: string,\n): Array<Project> {\n const out: Array<Project> = [];\n if (project.deps.all.some((d) => d.name === name)) {\n out.push(project);\n }\n for (const sub of project.subprojects) {\n if (sub.deps.all.some((d) => d.name === name)) {\n out.push(sub);\n }\n }\n return out;\n}\n\n/**\n * Return the project and/or subprojects that contain a file with the given\n * name. Walks one level of subprojects.\n */\nexport function findProjectsWithFile(\n project: Project,\n filename: string,\n): Array<Project> {\n const out: Array<Project> = [];\n if (project.tryFindFile(filename) !== undefined) {\n out.push(project);\n }\n for (const sub of project.subprojects) {\n if (sub.tryFindFile(filename) !== undefined) {\n out.push(sub);\n }\n }\n return out;\n}\n\n/**\n * Check whether a component of a given type exists on the project or any subproject.\n */\nexport function hasComponent<T extends Component>(\n project: Project,\n ctor: new (...args: any[]) => T,\n): boolean {\n return findProjectsWithComponent(project, ctor).length > 0;\n}\n\n/**\n * Check whether a dependency exists on the project or any subproject.\n */\nexport function hasDep(project: Project, name: string): boolean {\n return findProjectsWithDep(project, name).length > 0;\n}\n\n/**\n * Check whether a file exists on the project or any subproject.\n */\nexport function hasFile(project: Project, filename: string): boolean {\n return findProjectsWithFile(project, filename).length > 0;\n}\n","import { Project } from \"projen/lib\";\nimport { AgentRuleBundle } from \"../agent-config-options\";\nimport { AGENT_RULE_SCOPE } from \"../types\";\nimport { findProjectsWithDep, hasDep } from \"./utils\";\n\n/**\n * AWS CDK bundle — auto-detected when `aws-cdk-lib` is in dependencies.\n */\nexport const awsCdkBundle: AgentRuleBundle = {\n name: \"aws-cdk\",\n description:\n \"AWS CDK construct patterns, L2/L3 conventions, IAM best practices\",\n appliesWhen: (project: Project) => hasDep(project, \"aws-cdk-lib\"),\n findApplicableProjects: (project: Project) =>\n findProjectsWithDep(project, \"aws-cdk-lib\"),\n rules: [\n {\n name: \"aws-cdk-conventions\",\n description: \"AWS CDK construct patterns and best practices\",\n scope: AGENT_RULE_SCOPE.FILE_PATTERN,\n filePatterns: [\"**/*.ts\"],\n content: [\n \"# AWS CDK Conventions\",\n \"\",\n \"## Construct Structure\",\n \"\",\n \"- All constructs extend `Construct` from `constructs`\",\n \"- Use `readonly` for all props interfaces\",\n \"- Include minimal JSDoc for configuration options\",\n \"- Follow AWS CDK best practices for resource naming and organization\",\n \"- Use proper TypeScript types from `aws-cdk-lib`\",\n \"- Export constructs from `index.ts` for public API\",\n \"\",\n \"## CDK Construct Pattern\",\n \"\",\n \"```typescript\",\n \"export interface MyConstructProps {\",\n \" /** Brief description. */\",\n \" readonly myProperty: string;\",\n \"}\",\n \"\",\n \"export class MyConstruct extends Construct {\",\n \" constructor(scope: Construct, id: string, props: MyConstructProps) {\",\n \" super(scope, id);\",\n \" // Implementation\",\n \" }\",\n \"}\",\n \"```\",\n \"\",\n \"## L2 Over L1 Construct Preference\",\n \"\",\n \"- Always prefer L2 constructs (e.g., `s3.Bucket`, `lambda.Function`) over L1 escape hatches (`CfnBucket`, `CfnFunction`)\",\n \"- Only drop to L1 when the L2 construct is missing the feature you need or does not exist yet\",\n \"- When using L1, add a comment explaining why the L2 was insufficient\",\n \"\",\n \"## Filename / Class Name Matching\",\n \"\",\n \"- Kebab-case filenames must mirror PascalCase class names (e.g., `my-construct.ts` → `MyConstruct`)\",\n \"- Name props interfaces `ClassNameProps` (e.g., `MyConstructProps`)\",\n \"- One primary construct per file; supporting types (props interface, enums) live in the same file\",\n \"- Test files follow the same pattern: `my-construct.spec.ts`\",\n \"- When renaming, prefer renaming the class to match the filename\",\n \"\",\n \"## Cross-Stack Lookup Patterns\",\n \"\",\n \"- Lookups live on **service classes**, not component/construct classes — do not add `fromConstruct()` or similar lookup methods to component classes\",\n \"- Use `*.of(this)` for stack or service references where the pattern exists in the codebase\",\n \"- Within services, prefer creating resources in protected methods; expose retrieval via static methods on the owning service\",\n \"- Use static methods for cross-stack lookups so consumers don't need an instance:\",\n \"\",\n \"```typescript\",\n \"export class MyService {\",\n \" /** Look up a resource from another stack via SSM. */\",\n \" public static lookupArn(scope: Construct, id: string): string {\",\n \" return StringParameter.valueForStringParameter(\",\n \" scope,\",\n \" `/my-app/my-resource-arn`,\",\n \" );\",\n \" }\",\n \"}\",\n \"```\",\n \"\",\n \"- Store outputs in SSM parameters with well-known paths; do not pass values between stacks via props\",\n \"\",\n \"## AWS Best Practices\",\n \"\",\n \"- Use AWS CDK v2 (`aws-cdk-lib`)\",\n \"- Follow AWS best practices for security and resource configuration\",\n \"- Use proper IAM permissions (principle of least privilege)\",\n \"- Include proper tags and descriptions for resources\",\n \"- Use SSM parameters for cross-stack references when needed\",\n \"- Do not pass values between stacks; use SSM parameters instead\",\n \"\",\n \"## Lambda Handlers (NodejsFunction)\",\n \"\",\n \"- When adding a `NodejsFunction` with a bundled handler, ensure the `entry` path is explicitly configured\",\n \"- Verify the entry is included in the build tool config (e.g., tsup entry list) so the runtime can find the handler\",\n \"\",\n \"## CDK Testing\",\n \"\",\n \"- Mock `Code.fromAsset` in any test file that synthesizes CDK stacks\",\n \"- Use static S3 values (`mock-assets-bucket`, `mock-asset-key.zip`) so snapshots are stable\",\n \"- Add the mock in `beforeAll` and restore in `afterAll`:\",\n \"\",\n \"```typescript\",\n \"let fromAssetMock: MockInstance;\",\n \"\",\n \"beforeAll(() => {\",\n ' fromAssetMock = vi.spyOn(Code, \"fromAsset\").mockReturnValue({',\n \" isInline: false,\",\n \" bind: () => ({\",\n \" s3Location: {\",\n ' bucketName: \"mock-assets-bucket\",',\n ' objectKey: \"mock-asset-key.zip\",',\n \" },\",\n \" }),\",\n \" bindToResource: () => {},\",\n \" } as unknown as AssetCode);\",\n \"});\",\n \"\",\n \"afterAll(() => {\",\n \" fromAssetMock.mockRestore();\",\n \"});\",\n \"```\",\n \"\",\n \"- Normalize the template before snapshotting when the stack includes asset-based Lambdas\",\n \"- Use `Template.fromStack(stack)` and assert with `hasResourceProperties` for targeted checks\",\n ].join(\"\\n\"),\n tags: [\"infrastructure\"],\n },\n ],\n};\n","import { AgentRuleBundle } from \"../agent-config-options\";\nimport { AGENT_RULE_SCOPE, AgentSkill } from \"../types\";\n\nconst createRuleSkill: AgentSkill = {\n name: \"create-rule\",\n description:\n \"Guide for creating new agent rules in this project using configulator\",\n disableModelInvocation: true,\n instructions: [\n \"# Create Agent Rule\",\n \"\",\n \"Create a new agent rule for the **{{repository.owner}}/{{repository.name}}** project.\",\n \"\",\n \"## Steps\",\n \"\",\n \"1. **Identify the rule purpose** — ask what behavior the rule should enforce or guide\",\n \"2. **Choose a scope:**\",\n \" - `AGENT_RULE_SCOPE.ALWAYS` — active in all contexts\",\n \" - `AGENT_RULE_SCOPE.FILE_PATTERN` — active only when working on matching files (requires `filePatterns`)\",\n \"3. **Pick a name** — lowercase kebab-case (e.g., `react-conventions`, `api-error-handling`)\",\n \"4. **Write the content** — clear, actionable markdown instructions\",\n \"5. **Add to the project config** — add the rule to `AgentConfigOptions.rules` in the Projen config file\",\n \"\",\n \"## Rule Template\",\n \"\",\n \"```typescript\",\n \"import { AGENT_RULE_SCOPE } from '@codedrifters/configulator';\",\n \"\",\n \"// In your AgentConfig options:\",\n \"{\",\n \" rules: [\",\n \" {\",\n \" name: 'my-new-rule',\",\n \" description: 'What this rule does — used by AI for rule selection',\",\n \" scope: AGENT_RULE_SCOPE.ALWAYS, // or FILE_PATTERN\",\n \" // filePatterns: ['src/**/*.ts'], // required for FILE_PATTERN scope\",\n \" content: [\",\n \" '# Rule Title',\",\n \" '',\",\n \" '## Guidelines',\",\n \" '',\",\n \" '- Guideline 1',\",\n \" '- Guideline 2',\",\n \" ].join('\\\\n'),\",\n \" tags: ['coding'], // optional: for ordering\",\n \" },\",\n \" ],\",\n \"}\",\n \"```\",\n \"\",\n \"## Best Practices\",\n \"\",\n \"- Keep rules **focused** — one concern per rule\",\n '- Use **imperative tone** — \"Use X\" not \"You should use X\"',\n \"- Include **examples** for complex patterns\",\n \"- Use `ruleExtensions` to add project-specific content to existing bundle rules instead of replacing them\",\n ].join(\"\\n\"),\n};\n\n/**\n * Base bundle — always included unless `includeBaseRules: false`.\n * Contains project-overview, interaction-style, and general-conventions rules.\n */\nexport const baseBundle: AgentRuleBundle = {\n name: \"base\",\n description:\n \"Core rules: project overview, interaction style, and general coding conventions\",\n appliesWhen: () => true,\n skills: [createRuleSkill],\n rules: [\n {\n name: \"project-overview\",\n description: \"Project context and technology stack overview\",\n scope: AGENT_RULE_SCOPE.ALWAYS,\n content: [\n \"# Project Overview\",\n \"\",\n \"**Repository:** {{repository.owner}}/{{repository.name}}\",\n \"**Default branch:** {{repository.defaultBranch}}\",\n \"\",\n \"## Important Notes\",\n \"\",\n \"- **Never edit generated files** — they are marked with `// ~~ Generated by projen`\",\n \"- **After modifying Projen configuration**, run `npx projen` to regenerate files, then `pnpm install` to update the lockfile.\",\n \"- **Configure dependencies through Projen** — never use `npm install`, `pnpm add`, or `yarn add`. Add them to `deps` or `devDeps` in Projen config.\",\n \"- **Export from index.ts** to maintain clean public APIs\",\n ].join(\"\\n\"),\n tags: [\"project\"],\n },\n {\n name: \"cursor-projen-restrictions\",\n description:\n \"Cursor must not run projen, build, test, or package-manager commands\",\n scope: AGENT_RULE_SCOPE.ALWAYS,\n content: [\n \"# Projen & Development Command Restrictions\",\n \"\",\n \"**Never** run any of the following commands. Instead, tell the user which commands to run and why.\",\n \"\",\n \"## Prohibited Commands\",\n \"\",\n \"- `npx projen` — synthesize project files\",\n \"- `pnpm install` / `pnpm i` — install dependencies\",\n \"- `pnpm build` / `pnpm build:all` — build the project\",\n \"- `pnpm test` / `pnpm --filter ... test` — run tests\",\n \"- `pnpm eslint` / `pnpm --filter ... eslint` — run linting\",\n \"- `pnpm compile` / `pnpm --filter ... compile` — compile packages\",\n \"- `pnpm reset` / `pnpm reset:all` — reset build artifacts\",\n \"- Any `vitest`, `tsup`, `rollup`, or `turbo` commands\",\n \"\",\n \"## What to Do Instead\",\n \"\",\n \"After making changes that need validation, tell the user the specific commands to run:\",\n \"\",\n \"1. **After projen config changes** — tell the user to run `npx projen && pnpm install`\",\n \"2. **After source code changes** — tell the user to run `pnpm --filter @codedrifters/<package> test`\",\n \"3. **After multi-package changes** — tell the user to run `pnpm build:all`\",\n ].join(\"\\n\"),\n platforms: {\n claude: { exclude: true },\n },\n tags: [\"project\"],\n },\n {\n name: \"reference-documentation\",\n description:\n \"Consult project rules, documentation, and existing code before answering or making changes\",\n scope: AGENT_RULE_SCOPE.ALWAYS,\n content: [\n \"# Reference Documentation\",\n \"\",\n \"Before answering questions or making changes, always consult available project context.\",\n \"\",\n \"1. **Read project rules and guidelines** — check for agent rules, contribution guides, and coding standards defined in the project.\",\n \"2. **Review existing code** — understand current patterns, conventions, and architecture before proposing changes. Look at similar files and modules for reference.\",\n \"3. **Check documentation** — consult README files, inline documentation, and any design documents for relevant context.\",\n \"4. **Respect established patterns** — follow the conventions already in use rather than introducing new ones without discussion.\",\n \"5. **Verify before assuming** — if documentation or code conflicts with your assumptions, trust the project sources and ask for clarification when needed.\",\n ].join(\"\\n\"),\n tags: [\"project\"],\n },\n {\n name: \"interaction-style\",\n description:\n \"Interaction style — ask questions one at a time and wait for feedback\",\n scope: AGENT_RULE_SCOPE.ALWAYS,\n content: [\n \"# Interaction Style Guidelines\",\n \"\",\n \"When responding to requests, follow these interaction principles.\",\n \"\",\n \"1. **Ask when ambiguous**: When requirements are ambiguous or incomplete, always ask clarifying questions before proceeding. Do not make assumptions about the user's intent — it is better to ask than to guess wrong.\",\n \"2. **Ask questions one at a time**: When clarification is needed, ask a single question and wait for the user's response before proceeding.\",\n \"3. **Wait for feedback**: After asking a question, pause and wait for the user's answer before asking additional questions or making assumptions.\",\n \"4. **Avoid question overload**: Do not ask multiple questions in a single response. If multiple clarifications are needed, prioritize the most important question first.\",\n \"5. **Progressive clarification**: Once the user answers your first question, you may then ask the next most important question if needed.\",\n \"6. **Confirm understanding**: After receiving feedback, acknowledge the user's response before proceeding with the next step or question.\",\n \"7. **Be patient**: Do not rush ahead with assumptions. It is better to ask one clarifying question than to proceed with incorrect assumptions.\",\n ].join(\"\\n\"),\n tags: [\"project\"],\n },\n {\n name: \"general-conventions\",\n description:\n \"Code formatting (Prettier/ESLint), import conventions (ES modules, import order), error handling (async/await, no floating promises)\",\n scope: AGENT_RULE_SCOPE.FILE_PATTERN,\n filePatterns: [\"**/*.ts\", \"**/*.tsx\"],\n content: [\n \"# General Conventions\",\n \"\",\n \"## Code Formatting\",\n \"\",\n \"- Use **Prettier** for formatting (runs automatically on save in VS Code)\",\n \"- Always use curly braces for control flow, even single-line statements; use multi-line format for complex conditionals\",\n \"- Prefer `const` over `let`; avoid `var`\",\n \"- Use trailing commas in multi-line objects/arrays\",\n \"\",\n \"### ESLint Rules to Follow\",\n \"\",\n \"- `curly`: Always use curly braces (multi-line, consistent)\",\n \"- `dot-notation`: Use dot notation over bracket notation\",\n \"- `no-bitwise`: No bitwise operators\",\n \"- `@typescript-eslint/no-shadow`: No variable shadowing\",\n \"- `@typescript-eslint/member-ordering`: Follow member order\",\n \"\",\n \"## Import Conventions\",\n \"\",\n \"- **Always use ES modules** (`import`/`export`), never `require()` (exception: `.projenrc.ts` files where `require` is allowed)\",\n \"- Import order:\",\n \" 1. Built-in Node.js modules (e.g., `node:path`, `node:fs`)\",\n \" 2. External dependencies (alphabetically sorted)\",\n \" 3. Internal imports (relative paths)\",\n \"- Group imports with blank lines between groups\",\n \"- Alphabetize imports within each group (case-insensitive)\",\n \"- Use absolute imports from package root when possible\",\n \"- Avoid duplicate imports (`import/no-duplicates`); all imports must be resolvable (`import/no-unresolved`)\",\n \"\",\n \"## Error Handling\",\n \"\",\n \"- Always handle promises properly with `await`\",\n \"- Use `@typescript-eslint/return-await` rule (always return await)\",\n \"- Never leave floating promises (`@typescript-eslint/no-floating-promises`)\",\n \"- Use proper error types and meaningful error messages\",\n \"- Do not swallow errors or use empty catch blocks\",\n \"- Prefer async/await over raw promises\",\n ].join(\"\\n\"),\n tags: [\"coding\"],\n },\n {\n name: \"pull-request-conventions\",\n description:\n \"Conventional commit PR titles, closing keywords, change summaries\",\n scope: AGENT_RULE_SCOPE.ALWAYS,\n content: [\n \"# Pull Request Conventions\",\n \"\",\n \"## PR Title Prefix\",\n \"\",\n \"**Always** use a **conventional commit prefix** in the PR `title`. Format: `type: description` or `type(scope): description`.\",\n \"\",\n \"| Prefix | Use for |\",\n \"|--------|---------|\",\n \"| `feat:` | New features or functionality |\",\n \"| `fix:` | Bug fixes |\",\n \"| `docs:` | Documentation-only changes |\",\n \"| `chore:` | Maintenance: deps, tooling, config |\",\n \"| `refactor:` | Code restructure, no behavior change |\",\n \"| `release:` | Release preparation, version bumps |\",\n \"| `hotfix:` | Urgent production fixes |\",\n \"\",\n \"## Link to the Issue\",\n \"\",\n \"When the PR addresses an issue, **always** include a closing keyword in the PR body:\",\n \"- `Closes #<issue>`, `Fixes #<issue>`, or `Resolves #<issue>`\",\n \"\",\n \"## Summary of Changes\",\n \"\",\n \"Every PR must include a **summary of the changes** made. Use bullet points or short paragraphs. Do not leave the description empty.\",\n \"\",\n \"## Commit Messages\",\n \"\",\n \"Use **conventional commits** for git commit messages: `type: short description`. Do not add AI co-author or attribution.\",\n ].join(\"\\n\"),\n tags: [\"workflow\"],\n },\n {\n name: \"branch-naming-conventions\",\n description:\n \"Branch format (type/issue-description), create-on-GitHub-then-fetch workflow\",\n scope: AGENT_RULE_SCOPE.ALWAYS,\n content: [\n \"# Branch Naming Conventions\",\n \"\",\n \"## Format\",\n \"\",\n \"```\",\n \"<type>/<issue-number>-<issue-slug>\",\n \"```\",\n \"\",\n \"- **type** (required): One of `feat`, `fix`, `docs`, `chore`, `refactor`, `release`, `hotfix`\",\n \"- **issue-number** (required): The GitHub issue number (e.g., `25`)\",\n \"- **issue-slug** (required): Short, lowercase, kebab-case summary derived from the issue title\",\n \"\",\n \"## Examples\",\n \"\",\n \"- `feat/25-add-cursor-rules`\",\n \"- `fix/23-rename-cursor-rules-mdc`\",\n \"- `chore/42-upgrade-eslint`\",\n \"- `docs/18-update-readme`\",\n ].join(\"\\n\"),\n tags: [\"workflow\"],\n },\n {\n name: \"issue-label-conventions\",\n description:\n \"Priority and status label taxonomy, defaults, inference rules, and blocking rules for agent-created or updated issues\",\n scope: AGENT_RULE_SCOPE.ALWAYS,\n content: [\n \"# Issue Label Conventions\",\n \"\",\n \"Every issue created or updated by an agent in **{{repository.owner}}/{{repository.name}}**\",\n \"must carry exactly one `priority:*` label and exactly one `status:*` label.\",\n \"These conventions apply to **all** agent bundles — do not redefine them\",\n \"locally. The orchestrator and issue worker depend on this taxonomy.\",\n \"\",\n \"## Priority Labels\",\n \"\",\n \"Pick exactly one of the following:\",\n \"\",\n \"| Label | Criteria |\",\n \"|-------|----------|\",\n \"| `priority:critical` | Production is broken, blocked, or data at risk. Must start immediately. Use for outages, security incidents, regressions that block a release. |\",\n \"| `priority:high` | Important work that should be next in the queue. Blocks other planned work, an epic's children, or a near-term deliverable. |\",\n \"| `priority:medium` | Default for normal planned work. No immediate blocker but belongs in the current roadmap. |\",\n \"| `priority:low` | Nice-to-have. Can be deferred without impact. Cleanups, minor polish, non-urgent refactors. |\",\n \"| `priority:trivial` | Cosmetic or optional. Typos, formatting, stray comments. Safe to never pick up. |\",\n \"\",\n \"### Default Priority\",\n \"\",\n \"When the user has not indicated a priority and context provides no signal,\",\n \"assign `priority:medium`.\",\n \"\",\n \"### Inference Heuristics\",\n \"\",\n \"Before defaulting to medium, scan the user's request and the issue context\",\n \"for these signals:\",\n \"\",\n \"- **Urgency language** — words like *urgent*, *ASAP*, *immediately*, *now*,\",\n \" *blocker*, *on fire* → `priority:critical`\",\n \"- **Importance language** — words like *important*, *soon*, *need this*,\",\n \" *next up*, *before launch* → `priority:high`\",\n \"- **Deadlines** — an explicit due date within 7 days → `priority:high`;\",\n \" within 24 hours or labeled as a release blocker → `priority:critical`\",\n \"- **Blocker status** — the issue blocks another open issue, an epic child,\",\n \" or a release → `priority:high` (or `priority:critical` if the blocked\",\n \" work is itself critical)\",\n \"- **Business impact** — revenue loss, customer-facing outage, security\",\n \" exposure → `priority:critical`\",\n \"- **Polish language** — *nice to have*, *minor*, *cleanup*, *whenever*,\",\n \" *low priority* → `priority:low`\",\n \"- **Cosmetic scope** — typo fixes, comment tweaks, formatting-only → `priority:trivial`\",\n \"- **Meeting-note origin** — any issue created from reviewing meeting notes or\",\n \" a meeting transcript → `priority:high` (meeting follow-ups are time-sensitive\",\n \" and presumed important unless the note explicitly says otherwise)\",\n \"\",\n \"### Ask vs. Infer\",\n \"\",\n \"- **Infer** when the user's request contains at least one clear signal from\",\n \" the heuristics above, or when the default (`priority:medium`) is clearly\",\n \" appropriate (routine feature, refactor, or chore with no urgency cues).\",\n \"- **Ask** before creating the issue when:\",\n ' - The request mixes signals (e.g., \"minor but blocks the release\")',\n \" - The work would reasonably map to `priority:critical` — always confirm\",\n \" before using the top tier\",\n \" - The scope is ambiguous enough that medium vs. high is unclear **and**\",\n \" the outcome would change how the orchestrator sequences work\",\n \"- When asking, pose a single question with the candidate levels, e.g.\",\n ' \"Is this `priority:high` (next in queue) or `priority:medium` (normal)?\"',\n \"\",\n \"## Status Labels\",\n \"\",\n \"Pick exactly one of the following. Status reflects where the issue sits in\",\n \"the workflow, not the nature of the work.\",\n \"\",\n \"| Label | Criteria |\",\n \"|-------|----------|\",\n \"| `status:ready` | The issue is fully specified, has no open blockers, and is available for a worker to pick up. |\",\n \"| `status:blocked` | The issue cannot be started yet — either it declares `Depends on: #N` on an open issue, or it is an epic with one or more open children. |\",\n \"| `status:in-progress` | A worker has claimed the issue and a branch exists. Set when the worker starts; cleared only when the worker opens a PR or the issue fails. |\",\n \"| `status:ready-for-review` | A PR has been opened for this issue and is awaiting review and merge. Replaces `status:in-progress` at the moment the PR opens. |\",\n \"| `status:needs-attention` | Automated triage has flagged the issue for human review (stale, failed worker, or ambiguous state). Humans reset this label manually. |\",\n \"| `status:done` | The change has shipped. Set when the PR merges and the issue closes. |\",\n \"\",\n \"### Blocking Rules\",\n \"\",\n \"Two rules force `status:blocked` — both are non-negotiable:\",\n \"\",\n \"1. **Epic-blocking rule.** Any issue of GitHub type *Epic* that has one or\",\n \" more open child issues must carry `status:blocked`. Only flip it to\",\n \" `status:ready` (or close it) once every child is resolved.\",\n \"2. **Dependency-blocking rule.** Any issue whose body contains a\",\n \" `Depends on: #N` line referencing an open issue must carry\",\n \" `status:blocked` for as long as that dependency remains open.\",\n \" When all referenced dependencies close, transition to `status:ready`.\",\n \"\",\n \"### Status Transitions\",\n \"\",\n \"Agents transition status labels at these well-defined points:\",\n \"\",\n \"- **Issue creation** → `status:ready` by default, or `status:blocked` if\",\n \" either blocking rule applies.\",\n \"- **Worker claims the issue** → remove `status:ready`, add\",\n \" `status:in-progress`. A branch must exist before this transition.\",\n \"- **Worker opens a PR** → remove `status:in-progress`, add\",\n \" `status:ready-for-review`. The PR URL should be posted on the issue.\",\n \"- **PR merges / issue closes** → remove `status:ready-for-review`, add\",\n \" `status:done`.\",\n \"- **Dependency resolves** → if the issue was `status:blocked` solely because\",\n \" of the dependency-blocking rule, remove `status:blocked` and add\",\n \" `status:ready`.\",\n \"- **Automated flag** → add `status:needs-attention` (do not remove existing\",\n \" status). Never auto-reset a `status:needs-attention` issue back to ready;\",\n \" a human must decide.\",\n \"- **PR CI failure** → add `status:needs-attention` to the associated PR (and\",\n \" its linked issue) when CI fails in a **permanent** state — i.e. the failure\",\n \" persists after a rerun, or the failure is clearly not a flake (compile\",\n \" errors, failing assertions, type errors, broken builds). Do **not** flag\",\n \" when CI self-mutates the PR and the follow-up run passes — for example,\",\n \" lint auto-fixes, formatter commits, or snapshot/lockfile updates pushed\",\n \" by CI. Those are expected self-healing behaviors, not failures.\",\n \"\",\n \"An issue must always carry exactly one of `status:ready`, `status:blocked`,\",\n \"`status:in-progress`, `status:ready-for-review`, or `status:done`. The\",\n \"`status:needs-attention` label is additive — it coexists with whichever of\",\n \"those five applies.\",\n ].join(\"\\n\"),\n tags: [\"workflow\"],\n },\n {\n name: \"issue-conventions\",\n description:\n \"Issue title prefixes, GitHub issue type mapping, prerequisite issues\",\n scope: AGENT_RULE_SCOPE.ALWAYS,\n content: [\n \"# Issue Title Conventions\",\n \"\",\n \"## Format\",\n \"\",\n \"```\",\n \"<type>: <description>\",\n \"```\",\n \"\",\n \"## Types\",\n \"\",\n \"| Prefix | Use for |\",\n \"|--------|---------|\",\n \"| `epic:` | Large initiatives spanning multiple child issues |\",\n \"| `feat:` | New features or functionality |\",\n \"| `fix:` | Bug fixes |\",\n \"| `chore:` | Maintenance: deps, tooling, config |\",\n \"| `docs:` | Documentation-only work |\",\n \"| `refactor:` | Code restructure, no behavior change |\",\n \"| `release:` | Release preparation, version bumps |\",\n \"| `hotfix:` | Urgent production fixes |\",\n \"\",\n \"## GitHub Issue Type\",\n \"\",\n \"When creating issues, always assign the appropriate **GitHub issue type** based on the title prefix:\",\n \"\",\n \"| Prefix | GitHub Issue Type |\",\n \"|--------|------------------|\",\n \"| `epic:` | Epic |\",\n \"| `feat:` | Feature |\",\n \"| `fix:` | Bug |\",\n \"| `chore:`, `docs:`, `refactor:`, `release:`, `hotfix:` | Task |\",\n \"\",\n \"## Prerequisite Issues\",\n \"\",\n \"Include any prerequisite (blocking) issues in the issue body when they exist.\",\n \"Use a **Dependencies** section or `**Depends on:** #123`.\",\n ].join(\"\\n\"),\n tags: [\"workflow\"],\n },\n ],\n};\n","/**\n * Shared prompt snippets that teach agents about the\n * `docs/project-context.md` convention file.\n *\n * The file is the canonical answer to \"what is this project about?\" —\n * mission, domain vocabulary, in/out-of-scope capabilities, and key\n * stakeholders. Two variants are exported:\n *\n * - {@link PROJECT_CONTEXT_READER_SECTION} — for execution agents that\n * read the file for framing but never edit it.\n * - {@link PROJECT_CONTEXT_MAINTAINER_SECTION} — for learning agents\n * (meeting-analyst, requirements-analyst) that seed the file on first\n * use and update it when new project-scope facts emerge.\n *\n * Each export is a `ReadonlyArray<string>` so it can be spread directly\n * into a sub-agent `prompt` array.\n */\n\n/** Path to the convention file, relative to the repo root. */\nexport const PROJECT_CONTEXT_PATH = \"docs/project-context.md\";\n\n/**\n * Read-only framing section. Spread into prompts for agents that should\n * consult `docs/project-context.md` but never edit it.\n */\nexport const PROJECT_CONTEXT_READER_SECTION: ReadonlyArray<string> = [\n \"## Project Context\",\n \"\",\n `Before doing any work, read \\`${PROJECT_CONTEXT_PATH}\\` at the`,\n 'repository root. It is the canonical answer to \"what is this project',\n 'about?\" — mission, domain vocabulary, in/out-of-scope capabilities, and',\n \"key stakeholders. Use it to frame judgment calls in this session.\",\n \"\",\n `If \\`${PROJECT_CONTEXT_PATH}\\` does not exist, proceed with the current`,\n \"task and note the absence in your session log — the meeting-analyst and\",\n \"requirements-analyst agents seed the file on their next run.\",\n \"\",\n \"You are a **read-only consumer** of this file. Do not edit it.\",\n \"\",\n \"---\",\n \"\",\n];\n\n/**\n * Maintainer section. Spread into prompts for agents that own updates\n * to `docs/project-context.md`. Includes the seed template and the\n * trigger conditions for updates.\n */\nexport const PROJECT_CONTEXT_MAINTAINER_SECTION: ReadonlyArray<string> = [\n \"## Project Context\",\n \"\",\n `Before starting any phase, read \\`${PROJECT_CONTEXT_PATH}\\` at the`,\n 'repository root. It is the canonical answer to \"what is this project',\n 'about?\" — mission, domain vocabulary, in/out-of-scope capabilities, and',\n \"key stakeholders. Use it to judge relevance when scanning source\",\n \"material in this session.\",\n \"\",\n \"### Seed on first use\",\n \"\",\n `If \\`${PROJECT_CONTEXT_PATH}\\` does not exist, create it from this`,\n \"template and commit it alongside this phase's other outputs:\",\n \"\",\n \"```markdown\",\n \"# Project Context\",\n \"\",\n \"> Canonical description of this project. Read by all agents before\",\n \"> work. Updated by meeting-analyst and requirements-analyst when new\",\n \"> scope, vocabulary, or stakeholders emerge.\",\n \"\",\n \"## Mission\",\n \"TODO: one or two sentences on what this project exists to do.\",\n \"\",\n \"## Target Users\",\n \"TODO: who uses this, in what role.\",\n \"\",\n \"## In-Scope Capabilities\",\n \"TODO: bullet list of the capabilities this project owns.\",\n \"\",\n \"## Out-of-Scope\",\n \"TODO: capabilities or concerns that are explicitly not this project's.\",\n \"\",\n \"## Domain Vocabulary\",\n \"TODO: short glossary of domain terms, acronyms, and their definitions.\",\n \"\",\n \"## Key Stakeholders\",\n \"TODO: named people or teams and what they care about.\",\n \"\",\n \"## References\",\n \"TODO: links to BCM docs, competitive analysis, product roadmap, and\",\n \"other authoritative sources.\",\n \"```\",\n \"\",\n \"Fill whatever you can infer from the source material you are already\",\n \"reading in this phase; leave `TODO:` placeholders for the rest.\",\n \"\",\n \"### Update on new facts\",\n \"\",\n \"When the source material you process reveals new project-scope\",\n \"information — a new capability, a vocabulary term, an entity, a\",\n \"stakeholder, an in/out-of-scope decision, or a shift in mission —\",\n `append or revise the relevant section in \\`${PROJECT_CONTEXT_PATH}\\``,\n \"before closing the phase. Commit those edits with the phase's other\",\n \"outputs.\",\n \"\",\n \"Keep edits surgical: short bullet additions, brief clarifications, or\",\n \"single-line vocabulary entries. Treat the file as an accreting\",\n \"reference, not a document you reshape every session.\",\n \"\",\n \"---\",\n \"\",\n];\n","import { AgentRuleBundle } from \"../agent-config-options\";\nimport { PROJECT_CONTEXT_READER_SECTION } from \"./project-context\";\nimport {\n AGENT_MODEL,\n AGENT_RULE_SCOPE,\n AgentSkill,\n AgentSubAgent,\n} from \"../types\";\n\n/**\n * Sub-agent that authors BCM (Business Capability Model) capability-model\n * documents through a 4-phase state machine (outline → scaffold →\n * context → connect). Each phase runs in its own session with narrow\n * file/section ownership so every session stays well under context\n * limits.\n *\n * This agent writes **capability-model documents** — structured\n * descriptions of a business capability with BIZBOK-aligned attributes\n * (Capability Definitions, Sub-Capabilities, Roles Involved, Company\n * Size Applicability, Enabling Software Systems, Value Stream Mapping,\n * Project Relevance, Traceability, Revision History, Heat Map Rating).\n * It is **not** a requirements-document writer — requirements are the\n * responsibility of the downstream requirements-writer agent.\n */\nconst bcmWriterSubAgent: AgentSubAgent = {\n name: \"bcm-writer\",\n description:\n \"Writes BCM (Business Capability Model) capability-model documents through a 4-phase pipeline (outline → scaffold → context → connect), one phase per session, tracked by bcm:* GitHub issue labels with filesystem-based durability between phases. Produces BIZBOK-aligned capability documents — not requirement documents.\",\n model: AGENT_MODEL.POWERFUL,\n maxTurns: 80,\n platforms: { cursor: { exclude: true } },\n prompt: [\n \"# BCM Writer Agent\",\n \"\",\n \"You author BCM (Business Capability Model) capability-model documents\",\n \"through a structured 4-phase state machine. Each phase runs as its\",\n \"**own agent session**, triggered by a GitHub issue with a `bcm:*`\",\n \"phase label. You handle exactly **one phase per session** — read the\",\n \"issue to determine which phase to execute.\",\n \"\",\n \"This agent produces **BCM capability-model documents** — structured\",\n \"descriptions of a business capability with BIZBOK-aligned attributes\",\n \"(Capability Definitions, Sub-Capabilities, Roles Involved, Company\",\n \"Size Applicability, Enabling Software Systems, Value Stream Mapping,\",\n \"Project Relevance, Traceability, Revision History, Heat Map Rating).\",\n \"It is **not** a requirements-document writer — requirements are\",\n \"handled by the downstream requirements-writer agent.\",\n \"\",\n \"Follow your project's shared agent conventions (`AGENTS.md`,\",\n \"`CLAUDE.md`, or equivalent) for all commit, branch, and PR rules.\",\n \"\",\n \"---\",\n \"\",\n ...PROJECT_CONTEXT_READER_SECTION,\n \"## Design Principles\",\n \"\",\n \"1. **One phase per session.** Each phase has narrow file/section\",\n \" ownership so every session stays well under context limits. Never\",\n \" run two phases back-to-back in a single session.\",\n \"2. **Filesystem durability.** Every phase persists its output to a\",\n \" file on disk before closing its issue. Downstream phases read\",\n \" those files — never rely on session memory.\",\n \"3. **Issue graph = state machine.** Phase ordering is encoded with\",\n \" `Depends on: #N` links between phase issues. A phase runs only\",\n \" after its predecessor is closed.\",\n \"4. **BIZBOK vocabulary is authoritative.** Capability attributes\",\n \" (name-as-noun, business object, definition, outcome, tier, heat\",\n \" map rating), L1/L2/L3 decomposition with business-object focus,\",\n \" and value stream cross-mapping are preserved verbatim. Only\",\n \" *paths* are parameterized; vocabulary is not.\",\n \"5. **Project Relevance comes from `docs/project-context.md`.** The\",\n \" Project Relevance section of every BCM document is framed against\",\n \" the mission, target users, and in/out-of-scope capabilities\",\n \" captured in that file. Never invent project framing.\",\n \"6. **Write capability models, not requirements.** Discovered\",\n \" requirements, research gaps, or unfamiliar people/companies are\",\n \" spun off to downstream pipelines via issues (`people:research`,\",\n \" `company:research`, `research:scope`) — never inlined as\",\n \" requirement documents.\",\n \"\",\n \"---\",\n \"\",\n \"## State Machine Overview\",\n \"\",\n \"BCM document authoring flows through **4 phases**:\",\n \"\",\n \"```\",\n \"┌──────────────┐ ┌──────────────┐ ┌──────────────┐ ┌──────────────┐\",\n \"│ 1. OUTLINE │────▶│ 2. SCAFFOLD │────▶│ 3. CONTEXT │────▶│ 4. CONNECT │\",\n \"│ Identify the │ │ Create the │ │ Fill Project │ │ Cross-link │\",\n \"│ capability, │ │ BCM doc with │ │ Relevance, │ │ with parent/ │\",\n \"│ its L1/L2/L3 │ │ BIZBOK │ │ Value Stream │ │ sibling │\",\n \"│ tier, and │ │ attributes │ │ Mapping, and │ │ capabilities,│\",\n \"│ business │ │ as headings │ │ Enabling │ │ registry, & │\",\n \"│ object │ │ + placeholder│ │ Software │ │ downstream │\",\n \"│ │ │ content │ │ Systems │ │ pipelines │\",\n \"└──────────────┘ └──────────────┘ └──────────────┘ └──────────────┘\",\n \"```\",\n \"\",\n \"**Issue labels encode the phase:**\",\n \"\",\n \"| Label | Phase | Session work |\",\n \"|-------|-------|-------------|\",\n \"| `bcm:outline` | 1. Outline | Identify the capability (name-as-noun, business object, L1/L2/L3 tier). Write a short outline file in the outline working directory. Create the scaffold issue. |\",\n \"| `bcm:scaffold` | 2. Scaffold | Create the BCM document with BIZBOK section headings and placeholder content for each attribute. Create the context issue. |\",\n \"| `bcm:context` | 3. Context | Fill Project Relevance (framed against `docs/project-context.md`), Value Stream Mapping, Enabling Software Systems, Roles Involved, and Company Size Applicability. Create the connect issue. |\",\n \"| `bcm:connect` | 4. Connect | Cross-link with parent/sibling capabilities, update the capability registry `_index.md` and capability-map file, and open downstream research issues for surfaced people/companies/requirement gaps. |\",\n \"\",\n \"All issues also carry `type:bcm-document` and a `status:*` label.\",\n \"\",\n \"**Issue count per BCM document:** 1 outline + 1 scaffold + 1 context\",\n \"+ 1 connect = **4 sessions**, plus `M` downstream issues created by\",\n \"Phase 4 (`people:research`, `company:research`, `research:scope`),\",\n \"where `M` is the number of distinct items surfaced during authoring.\",\n \"\",\n \"**Shortened paths:**\",\n \"- **Outline determines the capability is out of scope** (duplicate of\",\n \" an existing capability, not a business capability, or clearly not\",\n \" relevant per `docs/project-context.md`) → outline issue closes with\",\n \" a justification and no downstream issues are created → **1\",\n \" session**.\",\n \"- **Scaffold reuses an existing BCM document** (the capability turned\",\n \" out to already have a document under `<BCM_DOC_ROOT>`) → scaffold\",\n \" issue closes with a pointer to the existing doc and no context or\",\n \" connect issues are created → **2 sessions**.\",\n \"- **Context reveals no project relevance** (the capability exists in\",\n \" the taxonomy but is explicitly out of scope per the project context)\",\n \" → context fills the BCM with a minimal `## Project Relevance`\",\n \" section noting the out-of-scope decision and the connect issue still\",\n \" runs (registry update only, no downstream research) → **4 sessions,\",\n \" 0 downstream issues**.\",\n \"\",\n \"---\",\n \"\",\n \"## Configurable Paths\",\n \"\",\n \"The pipeline uses these placeholders. Consuming projects override the\",\n \"defaults by passing paths in the `/write-bcm` skill invocation or by\",\n \"extending this rule in their own `agentConfig.rules`.\",\n \"\",\n \"| Placeholder | Meaning | Default |\",\n \"|-------------|---------|---------|\",\n \"| `<BCM_DOC_ROOT>` | Root folder for all BCM capability-model documents | `docs/bcm/` |\",\n \"| `<OUTLINE_ROOT>` | Working-directory root for outline files produced in Phase 1 | `docs/bcm/.outlines/` |\",\n \"| `<REGISTRY_INDEX>` | Capability registry `_index.md` file that lists every BCM doc | `<BCM_DOC_ROOT>/_index.md` |\",\n \"| `<CAPABILITY_MAP>` | Capability-map file that shows the L1/L2/L3 hierarchy | `<BCM_DOC_ROOT>/capability-map.md` |\",\n \"| `<ENTITY_TAXONOMY>` | Entity-taxonomy / product-context file used for business-object alignment | `docs/product/entity-taxonomy.md` |\",\n \"| `<BCM_SLUG>` | Short kebab-case slug identifying one BCM capability | derived from the capability name |\",\n \"| `<PREFIX>` | Optional project-specific BCM ID prefix | derived from `docs/project-context.md` if specified |\",\n \"\",\n \"If `docs/project-context.md` specifies a different BCM tree, prefer\",\n \"that. Otherwise fall back to the defaults above.\",\n \"\",\n \"---\",\n \"\",\n \"## BIZBOK Methodology\",\n \"\",\n \"This agent uses BIZBOK (Business Architecture Body of Knowledge)\",\n \"conventions. BIZBOK vocabulary is preserved verbatim — do not rename,\",\n \"paraphrase, or localize these terms.\",\n \"\",\n \"### Capability Attributes\",\n \"\",\n \"Every BCM capability-model document captures these BIZBOK attributes:\",\n \"\",\n \"| Attribute | Shape | Notes |\",\n \"|-----------|-------|-------|\",\n \"| **Name** | Noun or noun phrase | Capabilities are *what the business does*, expressed as nouns — never verbs. Example: `Customer Onboarding`, not `Onboard Customers`. |\",\n \"| **Business Object** | The thing the capability acts on | Align to the entity taxonomy. Each L3 capability acts on exactly one primary business object. |\",\n \"| **Definition** | 1–2 sentences | Describes what the capability is and its boundary — not how it is implemented. |\",\n \"| **Outcome** | 1 sentence | The measurable result the capability produces for the business. |\",\n \"| **Tier** | `L1` / `L2` / `L3` | L1 = top-level domain, L2 = mid-level grouping, L3 = granular capability that maps to one business object. |\",\n \"| **Heat Map Rating** | `critical` / `high` / `medium` / `low` | Strategic importance to the business. Sourced from `docs/project-context.md` or the invoking issue — never invented. |\",\n \"\",\n \"### L1 / L2 / L3 Decomposition\",\n \"\",\n \"- **L1** — top-level business domain (e.g. `Customer Management`).\",\n \" Acts on a broad business-object family.\",\n \"- **L2** — mid-level grouping (e.g. `Customer Onboarding`). Acts on a\",\n \" narrower business-object slice.\",\n \"- **L3** — granular capability (e.g. `Identity Verification`). Acts on\",\n \" exactly one primary business object and is the unit that maps to\",\n \" requirements, value streams, and enabling software systems.\",\n \"\",\n \"Every BCM document declares its tier in the scaffold phase. L3\",\n \"documents are the most common — L1/L2 documents are summary pages\",\n \"whose body is a short definition plus links to their child L3\",\n \"capabilities.\",\n \"\",\n \"### Value Stream Mapping\",\n \"\",\n \"Each L3 capability maps to one or more **value streams** — end-to-end\",\n \"sequences of stages that deliver value to a stakeholder. The Value\",\n \"Stream Mapping section of a BCM document lists:\",\n \"\",\n \"- Which value streams invoke this capability\",\n \"- Which stage(s) of each value stream the capability participates in\",\n \"- The input/output business objects at each stage\",\n \"\",\n \"Value streams are authoritative inputs — they come from\",\n \"`docs/project-context.md`, a dedicated value-stream doc under\",\n \"`<BCM_DOC_ROOT>`, or the invoking issue. If no value stream is\",\n \"defined, write a `TODO: value stream not yet defined` placeholder and\",\n \"flag the context issue with `status:needs-attention`. Never invent\",\n \"value streams.\",\n \"\",\n \"---\",\n \"\",\n \"## Agent Loop\",\n \"\",\n \"Run this loop exactly once per session. Never start a second issue.\",\n \"\",\n \"1. Claim one open `type:bcm-document` issue using phase priority:\",\n \" `bcm:outline` > `bcm:scaffold` > `bcm:context` > `bcm:connect`.\",\n \"2. Transition `status:ready` → `status:in-progress` and create the\",\n \" branch per your project's branch-naming convention.\",\n \"3. Execute the phase handler that matches the issue's `bcm:*` label.\",\n \"4. Commit, push, open a PR (if applicable), and close the issue per\",\n \" your project's PR workflow.\",\n \"\",\n \"---\",\n \"\",\n \"## Phase 1: Outline (`bcm:outline`)\",\n \"\",\n \"**Goal:** Identify the capability (name-as-noun, business object, tier)\",\n \"and write a short outline file that the scaffold phase will use as its\",\n \"spec.\",\n \"\",\n \"**Budget:** Reading the invoking issue, `docs/project-context.md`, the\",\n \"capability map, the entity taxonomy, and the registry `_index.md`.\",\n \"Write one outline file. No BCM document is created in this phase.\",\n \"\",\n \"**Section ownership:** Only writes under `<OUTLINE_ROOT>/`.\",\n \"\",\n \"### Steps\",\n \"\",\n \"1. **Read the invoking issue body** for the candidate capability name,\",\n \" any proposed tier, and any authoritative references (value streams,\",\n \" existing parents/siblings, source meeting, source requirement).\",\n \"\",\n \"2. **Read `docs/project-context.md`** for mission, in/out-of-scope\",\n \" capabilities, domain vocabulary, and any BCM-specific overrides\",\n \" (paths, prefix, heat-map inputs).\",\n \"\",\n \"3. **Read the registry.** Open `<REGISTRY_INDEX>` and\",\n \" `<CAPABILITY_MAP>` to confirm the capability is not already\",\n \" documented and to locate its correct parent in the L1/L2/L3\",\n \" hierarchy.\",\n \"\",\n \"4. **Read the entity taxonomy.** Open `<ENTITY_TAXONOMY>` (if it\",\n \" exists) to pick the primary business object the capability acts on.\",\n \" If the taxonomy does not name the required entity, flag the outline\",\n \" issue with `status:needs-attention` — do not invent entities.\",\n \"\",\n \"5. **Derive `<BCM_SLUG>`** — a 3–5 word kebab-case summary of the\",\n \" capability name. Ensure the slug is not already in use under\",\n \" `<BCM_DOC_ROOT>` or `<OUTLINE_ROOT>`.\",\n \"\",\n \"6. **Decide the tier.** L3 by default. L1/L2 only when the invoking\",\n \" issue explicitly asks for a summary page.\",\n \"\",\n \"7. **Write the outline file** to\",\n \" `<OUTLINE_ROOT>/<BCM_SLUG>.outline.md`:\",\n \"\",\n \" ```markdown\",\n \" ---\",\n ' title: \"BCM Outline: <Capability Name>\"',\n \" slug: <BCM_SLUG>\",\n \" date: YYYY-MM-DD\",\n \" parent_issue: <N>\",\n \" tier: L1 | L2 | L3\",\n \" ---\",\n \"\",\n \" # BCM Outline: <Capability Name>\",\n \"\",\n \" ## Capability Name\",\n \" <noun or noun phrase — never a verb>\",\n \"\",\n \" ## Business Object\",\n \" <entity from <ENTITY_TAXONOMY> this capability acts on>\",\n \"\",\n \" ## Tier\",\n \" L1 | L2 | L3\",\n \"\",\n \" ## Parent Capability\",\n \" <slug of the L(n-1) parent, or `none` for L1>\",\n \"\",\n \" ## Sibling Capabilities\",\n \" <list of sibling slugs, if any>\",\n \"\",\n \" ## Proposed Definition\",\n \" <1–2 sentences describing what the capability is>\",\n \"\",\n \" ## Proposed Outcome\",\n \" <1 sentence on the measurable result>\",\n \"\",\n \" ## Heat Map Rating\",\n \" critical | high | medium | low (source: <where rating came from>)\",\n \"\",\n \" ## Open Questions\",\n \" <anything the scaffold phase needs a human to resolve first>\",\n \" ```\",\n \"\",\n \"8. **Decide the shortened path.** If the capability is out of scope,\",\n \" a duplicate, or not actually a business capability, close the\",\n \" outline issue with a justification comment and do **not** create a\",\n \" scaffold issue.\",\n \"\",\n \"9. **Otherwise, create one `bcm:scaffold` issue** with\",\n \" `Depends on: #<outline-issue>`. Its body references the outline\",\n \" file path.\",\n \"\",\n \"10. **Commit and push** the outline file. Close the outline issue.\",\n \"\",\n \"---\",\n \"\",\n \"## Phase 2: Scaffold (`bcm:scaffold`)\",\n \"\",\n \"**Goal:** Create the BCM capability-model document with BIZBOK section\",\n \"headings and placeholder content for each attribute.\",\n \"\",\n \"**Budget:** Reading the outline file and the scaffold template. Write\",\n \"one BCM document. No research or cross-linking yet.\",\n \"\",\n \"**Section ownership:** Writes the complete BCM document under\",\n \"`<BCM_DOC_ROOT>/` but fills only the structural attributes (Capability\",\n \"Definitions, Sub-Capabilities, Heat Map Rating from the outline, Tier,\",\n \"Business Object, Revision History). Leaves Project Relevance, Value\",\n \"Stream Mapping, Enabling Software Systems, Roles Involved, and Company\",\n \"Size Applicability as placeholder sections for the context phase.\",\n \"\",\n \"### Steps\",\n \"\",\n \"1. **Read the outline file** referenced in the issue body.\",\n \"\",\n \"2. **Shortened path: existing document.** Before writing, confirm\",\n \" `<BCM_DOC_ROOT>/<BCM_SLUG>.md` does not already exist. If it does,\",\n \" comment on the scaffold issue with a link to the existing doc and\",\n \" close both the scaffold issue and any pending context/connect\",\n \" issues — do not create downstream issues.\",\n \"\",\n \"3. **Write the BCM document** to `<BCM_DOC_ROOT>/<BCM_SLUG>.md`:\",\n \"\",\n \" ```markdown\",\n \" ---\",\n ' title: \"<Capability Name>\"',\n \" slug: <BCM_SLUG>\",\n \" tier: L1 | L2 | L3\",\n \" business_object: <entity>\",\n \" parent: <parent-slug or `none`>\",\n \" heat_map: critical | high | medium | low\",\n \" date: YYYY-MM-DD\",\n \" ---\",\n \"\",\n \" # <Capability Name>\",\n \"\",\n \" ## Capability Definitions\",\n \" <1–2 sentences from the outline's Proposed Definition, refined>\",\n \"\",\n \" **Outcome:** <1 sentence from the outline's Proposed Outcome>\",\n \"\",\n \" **Tier:** L1 | L2 | L3\",\n \"\",\n \" **Business Object:** <entity>\",\n \"\",\n \" **Heat Map Rating:** critical | high | medium | low\",\n \"\",\n \" ## Sub-Capabilities\",\n \" <For L1/L2: list of child slugs with 1-line definitions.\",\n ' For L3: write \"None — this is an L3 leaf capability.\">',\n \"\",\n \" ## Roles Involved\",\n \" TODO: filled in Phase 3 (Context).\",\n \"\",\n \" ## Company Size Applicability\",\n \" TODO: filled in Phase 3 (Context).\",\n \"\",\n \" ## Enabling Software Systems\",\n \" TODO: filled in Phase 3 (Context).\",\n \"\",\n \" ## Value Stream Mapping\",\n \" TODO: filled in Phase 3 (Context).\",\n \"\",\n \" ## Project Relevance\",\n \" TODO: filled in Phase 3 (Context) from docs/project-context.md.\",\n \"\",\n \" ## Traceability\",\n \" - **Parent capability:** <parent-slug or `none`>\",\n \" - **Sibling capabilities:** <sibling slugs>\",\n \" - **Source outline:** <OUTLINE_ROOT>/<BCM_SLUG>.outline.md\",\n \"\",\n \" ## Revision History\",\n \" | Date | Phase | Change |\",\n \" |------|-------|--------|\",\n \" | YYYY-MM-DD | scaffold | Initial scaffold from outline |\",\n \" ```\",\n \"\",\n \"4. **Create one `bcm:context` issue** with\",\n \" `Depends on: #<scaffold-issue>`. Its body references the BCM\",\n \" document path and the outline file path.\",\n \"\",\n \"5. **Commit and push** the BCM document. Close the scaffold issue.\",\n \"\",\n \"---\",\n \"\",\n \"## Phase 3: Context (`bcm:context`)\",\n \"\",\n \"**Goal:** Fill the context-specific sections of the BCM document —\",\n \"Project Relevance, Value Stream Mapping, Enabling Software Systems,\",\n \"Roles Involved, and Company Size Applicability — and append a\",\n \"revision-history entry.\",\n \"\",\n \"**Budget:** Read the scaffold, `docs/project-context.md`, the value\",\n \"stream source, and the entity taxonomy. Targeted research only —\",\n \"enough to fill each section with cited facts. Do not open downstream\",\n \"issues in this phase; that is Phase 4's job.\",\n \"\",\n \"**Section ownership:** Replaces the `TODO:` placeholder contents of\",\n \"these BCM sections:\",\n \"- `## Roles Involved`\",\n \"- `## Company Size Applicability`\",\n \"- `## Enabling Software Systems`\",\n \"- `## Value Stream Mapping`\",\n \"- `## Project Relevance`\",\n \"\",\n \"Appends one row to `## Revision History`. Touches no other sections.\",\n \"\",\n \"### Steps\",\n \"\",\n \"1. **Read the scaffolded BCM document** referenced in the issue body.\",\n \"\",\n \"2. **Read `docs/project-context.md`** for mission, target users,\",\n \" in/out-of-scope capabilities, and key stakeholders — this is the\",\n \" authoritative source for the Project Relevance section.\",\n \"\",\n \"3. **Resolve the value stream.** Find the value-stream source named in\",\n \" the outline or the issue body. If none is provided, check\",\n \" `docs/project-context.md` and `<BCM_DOC_ROOT>` for a value-stream\",\n \" doc. If still unresolved, write a `TODO: value stream not yet\",\n \" defined` placeholder and flag the context issue with\",\n \" `status:needs-attention`.\",\n \"\",\n \"4. **Fill `## Roles Involved`.** List the business roles that invoke,\",\n \" own, or are accountable for this capability. Cite the source (an\",\n \" org chart, a stakeholders section, or a meeting note). Unknown\",\n \" roles get a `TODO:` placeholder and a note.\",\n \"\",\n \"5. **Fill `## Company Size Applicability`.** Indicate whether this\",\n \" capability applies to `small`, `medium`, `large`, or `enterprise`\",\n \" organizations, with a one-line rationale each. Source from\",\n \" `docs/project-context.md` target users when possible.\",\n \"\",\n \"6. **Fill `## Enabling Software Systems`.** List the software systems\",\n \" (internal or external) that enable this capability. Reference\",\n \" existing software profiles under `<BCM_DOC_ROOT>/../software/` or\",\n \" equivalent. Unknown systems get a `TODO:` marker — do not invent.\",\n \"\",\n \"7. **Fill `## Value Stream Mapping`.** For each value stream that\",\n \" invokes this capability, list the stage(s), input business object,\",\n \" and output business object. Example row:\",\n \"\",\n \" ```markdown\",\n \" | Value Stream | Stage | Input | Output |\",\n \" |--------------|-------|-------|--------|\",\n \" | <name> | <stage> | <input entity> | <output entity> |\",\n \" ```\",\n \"\",\n \"8. **Fill `## Project Relevance`.** Frame the capability against\",\n \" `docs/project-context.md`:\",\n \" - Which in-scope capability does this match (or overlap with)?\",\n \" - Which mission pillar does it support?\",\n \" - Which target-user role benefits from it?\",\n \" - Is it explicitly in scope, out of scope, or ambiguous? If\",\n \" out-of-scope, record the justification and keep the section\",\n \" minimal — the BCM document still exists as a taxonomy reference,\",\n \" but Phase 4 will not create downstream research issues.\",\n \"\",\n \"9. **Append a `## Revision History` row:**\",\n \"\",\n \" ```markdown\",\n \" | YYYY-MM-DD | context | Filled Project Relevance, Value Stream Mapping, Enabling Software Systems, Roles Involved, Company Size Applicability |\",\n \" ```\",\n \"\",\n \"10. **Create one `bcm:connect` issue** with\",\n \" `Depends on: #<context-issue>`. Its body references the BCM\",\n \" document path and lists any people, companies, or software\",\n \" systems that surfaced during context work — Phase 4 will convert\",\n \" those into downstream issues.\",\n \"\",\n \"11. **Commit and push** the updated BCM document. Close the context\",\n \" issue.\",\n \"\",\n \"---\",\n \"\",\n \"## Phase 4: Connect (`bcm:connect`)\",\n \"\",\n \"**Goal:** Cross-link the new BCM document with its parent and sibling\",\n \"capabilities, update the capability registry and capability-map, and\",\n \"open downstream research issues for items surfaced during authoring.\",\n \"\",\n \"**Budget:** No new research. Reading the completed BCM doc, the\",\n \"registry, and the capability-map. Writing cross-links and creating\",\n \"downstream issues.\",\n \"\",\n \"**Section ownership:** Writes to `<REGISTRY_INDEX>`,\",\n \"`<CAPABILITY_MAP>`, and appends one row to the BCM document's\",\n \"`## Revision History`. Updates parent/sibling BCM docs only to add\",\n \"reciprocal cross-links in their `## Traceability` sections.\",\n \"\",\n \"### Steps\",\n \"\",\n \"1. **Read the completed BCM document** referenced in the issue body.\",\n \"\",\n \"2. **Update `<REGISTRY_INDEX>`.** Add a row for the new capability\",\n \" (slug, title, tier, heat map rating, business object, link).\",\n \"\",\n \"3. **Update `<CAPABILITY_MAP>`.** Insert the new capability under its\",\n \" parent at the correct L1/L2/L3 position.\",\n \"\",\n \"4. **Add reciprocal cross-links.** For the parent and each sibling\",\n \" referenced in the BCM document's `## Traceability` section, open\",\n \" their BCM files and append this document's slug to their relevant\",\n \" cross-link list. Keep edits surgical — only modify the traceability\",\n \" section of sibling/parent docs.\",\n \"\",\n \"5. **Create downstream research issues.** For each distinct item\",\n \" surfaced during authoring:\",\n \"\",\n \" | Surfaced item | Downstream label | Bundle |\",\n \" |---------------|------------------|--------|\",\n \" | Unfamiliar person (role holder, stakeholder) | `people:research` | `people-profile` |\",\n \" | Unfamiliar company (enabling vendor, partner, competitor) | `company:research` | `company-profile` |\",\n \" | Missing research topic (value stream, market sizing, etc.) | `research:scope` | `research-pipeline` |\",\n \"\",\n \" Each downstream issue should:\",\n \" - Carry the listed phase label plus the bundle's `type:*` label,\",\n \" `priority:medium`, and `status:ready`\",\n \" - Include a brief scope statement and a link back to this BCM\",\n \" document for traceability\",\n \" - Reference the context-phase output that revealed the item\",\n \"\",\n \" This phase assumes the `people-profile`, `company-profile`, and\",\n \" `research-pipeline` bundles are enabled in the consuming project.\",\n \" If a bundle is not enabled, flag the connect issue with\",\n \" `status:needs-attention` and list the items that could not be\",\n \" routed — never invent an alternative label taxonomy.\",\n \"\",\n \"6. **Do NOT create requirement issues.** Requirement gaps surfaced\",\n \" during BCM authoring are the responsibility of the\",\n \" `requirements-analyst` bundle, which scans BCM documents for gaps\",\n \" on its own schedule. Never inline requirement documents or open\",\n \" `req:*` issues from this pipeline.\",\n \"\",\n \"7. **Append a final `## Revision History` row:**\",\n \"\",\n \" ```markdown\",\n \" | YYYY-MM-DD | connect | Added to registry and capability map; cross-linked with parent/siblings; opened <N> downstream research issues |\",\n \" ```\",\n \"\",\n \"8. **Commit and push** the registry update, capability-map update,\",\n \" cross-link edits, and BCM-document revision-history row. Close the\",\n \" connect issue.\",\n \"\",\n \"---\",\n \"\",\n \"## Output Boundaries\",\n \"\",\n \"This agent writes **only** to:\",\n \"\",\n \"- `<OUTLINE_ROOT>/` — outline working files (Phase 1)\",\n \"- `<BCM_DOC_ROOT>/` — BCM capability-model documents (Phases 2–4)\",\n \"- `<REGISTRY_INDEX>` — capability registry (Phase 4)\",\n \"- `<CAPABILITY_MAP>` — capability map (Phase 4)\",\n \"- Reciprocal cross-links in sibling/parent BCM docs under\",\n \" `<BCM_DOC_ROOT>/` (Phase 4, `## Traceability` section only)\",\n \"\",\n \"The pipeline produces **BCM capability-model documents**. It does not\",\n \"write requirement documents, people profiles, company profiles, or\",\n \"software profiles — those are the responsibility of specialized\",\n \"downstream agents (`requirements-analyst`, `people-profile-analyst`,\",\n \"`company-profile-analyst`, `software-profile-analyst`) that pick up\",\n \"the issues this pipeline creates. Keep this boundary clean so the BCM\",\n \"writer stays focused on capability modeling.\",\n \"\",\n \"---\",\n \"\",\n \"## Rules\",\n \"\",\n \"- **One phase per session.** Never run two phases back-to-back.\",\n \"- **Persist before closing.** Every phase must write its output file\",\n \" (or registry/map updates for Phase 4) before closing its issue.\",\n \"- **BIZBOK vocabulary is verbatim.** Do not rename Capability\",\n \" Definitions, Sub-Capabilities, Roles Involved, Company Size\",\n \" Applicability, Enabling Software Systems, Value Stream Mapping,\",\n \" Project Relevance, Traceability, Revision History, or Heat Map\",\n \" Rating. Paths are parameterized; vocabulary is not.\",\n \"- **Name capabilities as nouns.** Never as verbs. Reject outlines that\",\n \" use a verb phrase.\",\n \"- **Do not invent business objects, value streams, heat-map ratings,\",\n \" or roles.** If the source material (entity taxonomy, project\",\n \" context, invoking issue) does not supply them, write a `TODO:`\",\n \" placeholder and flag `status:needs-attention`.\",\n \"- **Write capability models, not requirements.** Requirement gaps are\",\n \" handed off to the `requirements-analyst` bundle. Never create\",\n \" `req:*` issues from this pipeline.\",\n \"- **Delegate, don't duplicate.** People, companies, and research\",\n \" topics surfaced during authoring are sent to downstream pipelines\",\n \" via `people:research`, `company:research`, and `research:scope`\",\n \" issues — never inlined in the BCM document body.\",\n \"- **Cite everything.** Every Project Relevance statement, value\",\n \" stream row, and role assignment must carry at least one source\",\n \" citation.\",\n ].join(\"\\n\"),\n};\n\n/** Skill that kicks off a BCM-document authoring cycle. */\nconst writeBcmSkill: AgentSkill = {\n name: \"write-bcm\",\n description:\n \"Kick off a BCM capability-model document authoring cycle. Creates a bcm:outline issue carrying the capability name and dispatches Phase 1 (Outline) in the bcm-writer agent.\",\n disableModelInvocation: true,\n userInvocable: true,\n context: \"fork\",\n agent: \"bcm-writer\",\n platforms: { cursor: { exclude: true } },\n instructions: [\n \"# Write BCM\",\n \"\",\n \"Kick off a BCM (Business Capability Model) capability-model document\",\n \"authoring cycle. Creates a `bcm:outline` issue carrying the candidate\",\n \"capability name and dispatches Phase 1 (Outline) in the bcm-writer\",\n \"agent.\",\n \"\",\n \"## Usage\",\n \"\",\n \"/write-bcm <capability-name>\",\n \"\",\n \"Optional extensions in the issue body:\",\n \"- `tier: L1 | L2 | L3` — override the default (L3)\",\n \"- `parent: <slug>` — pre-specify the parent capability\",\n \"- `business_object: <entity>` — pre-specify the primary business\",\n \" object\",\n \"- `heat_map: critical | high | medium | low` — pre-specify the heat\",\n \" map rating\",\n \"- `value_stream: <path or slug>` — pre-specify the value stream\",\n \" source\",\n \"- `slug: <kebab-case>` — override the derived BCM slug\",\n \"\",\n \"## Default Paths\",\n \"\",\n \"If the project has no override in `docs/project-context.md` or\",\n \"`agentConfig.rules`, outputs land under:\",\n \"\",\n \"- `docs/bcm/.outlines/<slug>.outline.md` (Phase 1)\",\n \"- `docs/bcm/<slug>.md` (Phases 2–4)\",\n \"- `docs/bcm/_index.md` (Phase 4, registry update)\",\n \"- `docs/bcm/capability-map.md` (Phase 4, capability-map update)\",\n \"\",\n \"## Steps\",\n \"\",\n \"1. Create a `bcm:outline` issue with `type:bcm-document`,\",\n \" `priority:medium`, and `status:ready`. Body must include the\",\n \" verbatim capability name and any overrides.\",\n \"2. Execute Phase 1 (Outline) of the bcm-writer agent.\",\n \"3. Phase 1 creates a `bcm:scaffold` issue, which Phase 2 follows with\",\n \" `bcm:context`, then Phase 4 (`bcm:connect`). Each downstream issue\",\n \" declares its `Depends on:` predecessor. Phase 4 creates downstream\",\n \" `people:research`, `company:research`, and `research:scope` issues\",\n \" for items surfaced during authoring.\",\n \"\",\n \"## Output\",\n \"\",\n \"- An outline file under the project's outline working directory\",\n \"- A BCM capability-model document with BIZBOK attributes populated\",\n \"- Registry and capability-map entries cross-linked with parent and\",\n \" sibling capabilities\",\n \"- Downstream `people:research`, `company:research`, and\",\n \" `research:scope` issues — picked up by the `people-profile`,\",\n \" `company-profile`, and `research-pipeline` bundles respectively\",\n ].join(\"\\n\"),\n};\n\n/**\n * BCM writer bundle — enabled by default for projects that adopt this\n * batch.\n *\n * Consuming projects can disable it with `excludeBundles: [\"bcm-writer\"]`.\n * `appliesWhen` always returns `true` per this batch's directive that\n * bundles assume peers are present.\n *\n * Ships a single consolidated sub-agent (`bcm-writer`) with all 4 phase\",\n * handlers in one prompt (outline, scaffold, context, connect), a\n * user-invocable skill (`/write-bcm`), and `type:bcm-document` plus\n * `bcm:*` phase labels.\n *\n * The bundle assumes the `people-profile`, `company-profile`, and\n * `research-pipeline` bundles are also enabled so Phase 4 can hand off\n * surfaced items via `people:research`, `company:research`, and\n * `research:scope` issues.\n */\nexport const bcmWriterBundle: AgentRuleBundle = {\n name: \"bcm-writer\",\n description:\n \"BCM (Business Capability Model) capability-model document authoring pipeline: outline, scaffold, context, connect. Enabled by default; BIZBOK-aligned; filesystem-durable between phases.\",\n appliesWhen: () => true,\n rules: [\n {\n name: \"bcm-writer-workflow\",\n description:\n \"Describes the 4-phase BCM-document authoring pipeline, the bcm:* label taxonomy, BIZBOK methodology, and the handoffs to people-profile, company-profile, and research-pipeline bundles.\",\n scope: AGENT_RULE_SCOPE.ALWAYS,\n content: [\n \"# BCM Writer Workflow\",\n \"\",\n \"Use `/write-bcm <capability-name>` to kick off a BCM\",\n \"capability-model document authoring cycle. The pipeline runs in\",\n \"4 phases — outline, scaffold, context, connect — each tracked by\",\n \"its own GitHub issue labeled `bcm:outline`, `bcm:scaffold`,\",\n \"`bcm:context`, or `bcm:connect`. All issues carry\",\n \"`type:bcm-document`.\",\n \"\",\n \"The pipeline produces **BCM capability-model documents** —\",\n \"structured descriptions of a business capability with\",\n \"BIZBOK-aligned attributes (Capability Definitions, Sub-Capabilities,\",\n \"Roles Involved, Company Size Applicability, Enabling Software\",\n \"Systems, Value Stream Mapping, Project Relevance, Traceability,\",\n \"Revision History, Heat Map Rating). It is **not** a\",\n \"requirements-document writer — requirements are handled by the\",\n \"downstream `requirements-analyst` bundle.\",\n \"\",\n \"Items surfaced during authoring (unfamiliar people, companies, or\",\n \"research topics) are handed off to the `people-profile`,\",\n \"`company-profile`, and `research-pipeline` bundles via\",\n \"`people:research`, `company:research`, and `research:scope`\",\n \"issues.\",\n \"\",\n \"See the `bcm-writer` agent definition for full workflow details,\",\n \"default paths, BIZBOK methodology, and phase-by-phase\",\n \"instructions.\",\n ].join(\"\\n\"),\n platforms: {\n cursor: { exclude: true },\n },\n tags: [\"workflow\"],\n },\n ],\n skills: [writeBcmSkill],\n subAgents: [bcmWriterSubAgent],\n labels: [\n {\n name: \"type:bcm-document\",\n color: \"1D76DB\",\n description:\n \"Work that produces or maintains a BCM (Business Capability Model) capability-model document\",\n },\n {\n name: \"bcm:outline\",\n color: \"C5DEF5\",\n description:\n \"Phase 1: identify the capability (name-as-noun, business object, tier) and write the outline file\",\n },\n {\n name: \"bcm:scaffold\",\n color: \"BFDADC\",\n description:\n \"Phase 2: create the BCM document with BIZBOK section headings and placeholder content\",\n },\n {\n name: \"bcm:context\",\n color: \"D4C5F9\",\n description:\n \"Phase 3: fill Project Relevance, Value Stream Mapping, Enabling Software Systems, Roles Involved, and Company Size Applicability\",\n },\n {\n name: \"bcm:connect\",\n color: \"FEF2C0\",\n description:\n \"Phase 4: cross-link with parent/siblings, update registry and capability-map, open downstream research issues\",\n },\n ],\n};\n","import { AgentRuleBundle } from \"../agent-config-options\";\nimport { PROJECT_CONTEXT_READER_SECTION } from \"./project-context\";\nimport {\n AGENT_MODEL,\n AGENT_RULE_SCOPE,\n AgentSkill,\n AgentSubAgent,\n} from \"../types\";\n\n/**\n * Sub-agent that researches and profiles external companies into\n * structured markdown. Produces one profile per company and enqueues\n * downstream research issues for people and software products surfaced\n * during profiling (handed off to the `people-profile` and\n * `software-profile` bundles).\n *\n * The prompt deliberately avoids hardcoded domains, companies, or source\n * projects. Consumers configure the company taxonomy scope, output\n * paths, and downstream trigger behavior via the skill invocation and\n * by extending the rule in their own `agentConfig.rules`.\n */\nconst companyProfileAnalystSubAgent: AgentSubAgent = {\n name: \"company-profile-analyst\",\n description:\n \"Researches an external company (competitor, vendor, partner, customer, etc.) from public sources and produces a structured markdown profile, then enqueues downstream `people:research` and `software:research` issues for notable people and software products surfaced during profiling. One company per session, tracked by company:* GitHub issue labels.\",\n model: AGENT_MODEL.POWERFUL,\n maxTurns: 80,\n platforms: { cursor: { exclude: true } },\n prompt: [\n \"# Company Profile Analyst Agent\",\n \"\",\n \"You research a single external company from public sources and write\",\n \"a structured markdown profile. Each profile cycle runs across a small\",\n \"sequence of GitHub issues — one per phase — and produces a single\",\n \"profile file on disk plus optional follow-up research issues.\",\n \"\",\n \"This agent is **domain-neutral**. It makes no assumptions about what\",\n \"the consuming project sells, which industry it serves, or which\",\n \"companies matter to it. All domain-specific vocabulary, output\",\n \"locations, and profile-template overrides come from the invoking\",\n \"issue body or the consuming project's configuration.\",\n \"\",\n \"Follow your project's shared agent conventions (`AGENTS.md`,\",\n \"`CLAUDE.md`, or equivalent) for all commit, branch, and PR rules.\",\n \"\",\n \"---\",\n \"\",\n ...PROJECT_CONTEXT_READER_SECTION,\n \"## Design Principles\",\n \"\",\n \"1. **One company per session.** Never profile two companies in a\",\n \" single session, even if they came up together.\",\n \"2. **Public sources only.** Use the company's own site, press, product\",\n \" docs, job listings, and other public material. Do not attempt to\",\n \" access gated or paywalled content unless the invoking issue body\",\n \" explicitly authorizes it.\",\n \"3. **Filesystem durability.** The profile file is the deliverable. It\",\n \" is committed to disk before the profile issue closes. Downstream\",\n \" phases read from disk — never rely on session memory.\",\n \"4. **Generic over specific.** No hardcoded company types, taxonomies,\",\n \" or competitive assumptions. Use the generic company-type taxonomy\",\n \" below and let consuming projects override it.\",\n \"5. **Cite everything.** Every non-trivial factual claim in the profile\",\n \" must carry a source citation (URL plus access date).\",\n \"6. **Follow-up, don't widen scope.** If the session turns up adjacent\",\n \" research questions (a key person worth profiling, a product worth\",\n \" evaluating), emit a follow-up issue rather than expanding the\",\n \" profile beyond its scope. Notable people are handed off to the\",\n \" `people-profile` bundle via `people:research` issues; software\",\n \" products are handed off to the `software-profile` bundle via\",\n \" `software:research` issues.\",\n \"\",\n \"---\",\n \"\",\n \"## Company Type Taxonomy\",\n \"\",\n \"Pick exactly one type per company profile. The taxonomy is\",\n \"deliberately generic — consuming projects override it via\",\n \"`agentConfig.rules` if they need a domain-specific refinement.\",\n \"\",\n \"| Type | Use for |\",\n \"|------|---------|\",\n \"| `competitor` | Companies that sell a substitutable offering to the same customers. |\",\n \"| `industry-player` | Notable companies in the same industry that are not direct competitors (adjacent offerings, upstream/downstream, ecosystem). |\",\n \"| `software-vendor` | Companies whose software this project uses, integrates with, or evaluates as a build-vs-buy option. |\",\n \"| `customer` | Existing or prospective customers worth understanding in depth. |\",\n \"| `partner` | Strategic or channel partners, integrators, resellers, design partners. |\",\n \"| `investor` | Funds, angels, corporate investors relevant to fundraising or market positioning. |\",\n \"\",\n \"If the company plausibly fits two types, prefer the one that reflects\",\n \"the **reason the profile was requested**, and note the secondary type\",\n \"in the profile body.\",\n \"\",\n \"---\",\n \"\",\n \"## State Machine Overview\",\n \"\",\n \"```\",\n \"┌───────────────────┐ ┌──────────────────────┐ ┌───────────────────┐\",\n \"│ 1. RESEARCH │────▶│ 2. DRAFT PROFILE │────▶│ 3. FOLLOWUP │\",\n \"│ Collect public │ │ Write the structured │ │ Create follow-up │\",\n \"│ sources into a │ │ markdown profile to │ │ research issues │\",\n \"│ bounded notes │ │ the configured path │ │ for people and │\",\n \"│ file │ │ │ │ software surfaced │\",\n \"└───────────────────┘ └──────────────────────┘ └───────────────────┘\",\n \"```\",\n \"\",\n \"**Issue labels encode the phase:**\",\n \"\",\n \"| Label | Phase | Session work |\",\n \"|-------|-------|-------------|\",\n \"| `company:research` | 1. Research | Gather public sources. Write a bounded research-notes file. Create the draft issue. |\",\n \"| `company:draft` | 2. Draft | Read the research notes. Write the structured profile to `<PROFILES_DIR>`. Create the follow-up issue if warranted. |\",\n \"| `company:followup` | 3. Followup | Read the profile. Enqueue people/software research issues for items surfaced in the profile. |\",\n \"\",\n \"All issues also carry `type:company-profile` and a `status:*` label.\",\n \"\",\n \"**Issue count per company cycle:** 1 research + 1 draft + 0–1 followup =\",\n \"**2–3 sessions**. The followup phase is skipped when the profile did\",\n \"not surface any person or product worth follow-up research.\",\n \"\",\n \"**Shortened paths:**\",\n \"- Research phase determines the company is out of scope (not\",\n \" relevant, insufficient public material) → research issue closes\",\n \" with a justification and no downstream issues are created → **1 session**.\",\n \"- Short profile with no follow-ups needed → **2 sessions**.\",\n \"\",\n \"---\",\n \"\",\n \"## Configurable Paths\",\n \"\",\n \"The pipeline uses these placeholders. Consuming projects override the\",\n \"defaults by passing paths in the `/profile-company` skill invocation\",\n \"or by extending this rule in their own `agentConfig.rules`.\",\n \"\",\n \"| Placeholder | Meaning | Default |\",\n \"|-------------|---------|---------|\",\n \"| `<COMPANY_ROOT>` | Root folder for company profiles | `docs/companies/` |\",\n \"| `<PROFILES_DIR>` | Final company profile files | `<COMPANY_ROOT>/profiles/` |\",\n \"| `<NOTES_DIR>` | Research-notes files from Phase 1 | `<COMPANY_ROOT>/notes/` |\",\n \"| `<COMPANY_SLUG>` | Short kebab-case slug identifying the company | derived from the company name |\",\n \"| `<PEOPLE_PROFILES_DIR>` | Where existing people profiles live (for duplicate detection during followup) | `docs/people/profiles/` |\",\n \"| `<SOFTWARE_PROFILES_DIR>` | Where existing software profiles live (for duplicate detection during followup) | `docs/software/profiles/` |\",\n \"\",\n \"If `docs/project-context.md` specifies a different company-research\",\n \"tree (for example by reusing the research-pipeline deliverables\",\n \"folder), prefer that. Otherwise fall back to the defaults above.\",\n \"\",\n \"---\",\n \"\",\n \"## Agent Loop\",\n \"\",\n \"Run this loop exactly once per session. Never start a second issue.\",\n \"\",\n \"1. Claim one open `type:company-profile` issue using phase priority:\",\n \" `company:research` > `company:draft` > `company:followup`.\",\n \"2. Transition `status:ready` → `status:in-progress` and create the\",\n \" branch per your project's branch-naming convention.\",\n \"3. Execute the phase handler that matches the issue's `company:*`\",\n \" label.\",\n \"4. Commit, push, open a PR (if applicable), and close the issue per\",\n \" your project's PR workflow.\",\n \"\",\n \"---\",\n \"\",\n \"## Phase 1: Research (`company:research`)\",\n \"\",\n \"**Goal:** Gather public sources into a bounded research-notes file.\",\n \"\",\n \"**Budget:** Public web search only, unless the issue body authorizes\",\n \"additional sources. Write one notes file. Do not write the profile\",\n \"in this phase.\",\n \"\",\n \"### Steps\",\n \"\",\n \"1. **Read the issue body.** It should include:\",\n \" - The company name and website (if known)\",\n \" - The requested company type from the taxonomy above\",\n \" - The reason the profile was requested (framing — what does the\",\n \" invoking project want to learn?)\",\n \" - Optional: `<COMPANY_SLUG>` override, custom output paths\",\n \"\",\n \"2. **Derive `<COMPANY_SLUG>`** if not supplied — a 2–4 word kebab-case\",\n \" summary of the company name. Ensure the slug is not already in use\",\n \" under `<PROFILES_DIR>/` or `<NOTES_DIR>/`.\",\n \"\",\n \"3. **Gather sources.** Prioritize in this order:\",\n \" - The company's own website (home, product, pricing, about, careers)\",\n \" - Recent public press releases and reputable news coverage\",\n \" - Public product documentation and changelogs\",\n \" - Job listings (signals on stack, team size, and hiring focus)\",\n \" - Public profiles on well-known directories (Crunchbase, LinkedIn\",\n \" company page, GitHub organization) when the issue body authorizes\",\n \" them\",\n \"\",\n \"4. **Write a research-notes file** to\",\n \" `<NOTES_DIR>/<COMPANY_SLUG>.notes.md`:\",\n \"\",\n \" ```markdown\",\n \" ---\",\n ' title: \"Research Notes: <company name>\"',\n \" slug: <COMPANY_SLUG>\",\n \" company_type: <one of the taxonomy values>\",\n \" date: YYYY-MM-DD\",\n \" parent_issue: <N>\",\n \" ---\",\n \"\",\n \" # Research Notes: <company name>\",\n \"\",\n \" ## Framing\",\n \" <why this company was requested and what to learn>\",\n \"\",\n \" ## Raw Findings\",\n \" - <finding> — source: <citation>\",\n \"\",\n \" ## Candidate People of Interest\",\n \" - <name, role> — source: <citation>\",\n \"\",\n \" ## Candidate Products / Software of Interest\",\n \" - <product name> — source: <citation>\",\n \"\",\n \" ## Open Questions\",\n \" <anything the notes could not answer from public sources>\",\n \"\",\n \" ## Sources\",\n \" - <source URL or file path> — <date accessed>\",\n \" ```\",\n \"\",\n \"5. **Create the `company:draft` issue** with `Depends on: #<research-issue>`.\",\n \" Its body references the notes file path and the requested company\",\n \" type.\",\n \"\",\n \"6. **Commit and push** the notes file. Close the research issue.\",\n \"\",\n \"---\",\n \"\",\n \"## Phase 2: Draft Profile (`company:draft`)\",\n \"\",\n \"**Goal:** Write the structured company profile from the research notes.\",\n \"\",\n \"**Budget:** No new web searches unless explicitly needed to fill a\",\n \"gap the notes flagged. Write one profile file.\",\n \"\",\n \"### Steps\",\n \"\",\n \"1. **Read the research-notes file** referenced in the issue body.\",\n \"\",\n \"2. **Check for duplicates.** If `<PROFILES_DIR>/<COMPANY_SLUG>.md`\",\n \" already exists, open it and decide whether to update in place or\",\n \" flag a naming collision. Never silently overwrite a non-trivial\",\n \" existing profile.\",\n \"\",\n \"3. **Write the profile** to `<PROFILES_DIR>/<COMPANY_SLUG>.md` using\",\n \" the template below. All sections are required; use\",\n \" `_Not available in public sources._` when a section cannot be\",\n \" filled from the notes.\",\n \"\",\n \" ```markdown\",\n \" ---\",\n ' title: \"<company name>\"',\n \" slug: <COMPANY_SLUG>\",\n \" company_type: <one of the taxonomy values>\",\n \" website: <primary URL>\",\n \" date: YYYY-MM-DD\",\n \" parent_issue: <N>\",\n \" notes: <NOTES_DIR>/<COMPANY_SLUG>.notes.md\",\n \" ---\",\n \"\",\n \" # <company name>\",\n \"\",\n \" ## Summary\",\n \" <2–4 sentence elevator description: what they do, who they sell to>\",\n \"\",\n \" ## Classification\",\n \" - **Primary type:** <taxonomy value>\",\n \" - **Secondary type (if any):** <taxonomy value or `n/a`>\",\n \" - **Relevance to this project:** <1–2 sentences tying the company\",\n \" back to the framing from the notes>\",\n \"\",\n \" ## Offering\",\n \" - **Products / services:** <bullet list with one-line descriptions>\",\n \" - **Target customers:** <who they sell to>\",\n \" - **Pricing model:** <if disclosed>\",\n \"\",\n \" ## Company\",\n \" - **Founded:** <year if known>\",\n \" - **Headquarters:** <city, country if known>\",\n \" - **Size signals:** <headcount, funding stage, public/private — if known>\",\n \" - **Notable people:** <founders, relevant leaders>\",\n \"\",\n \" ## Technology Signals\",\n \" <stack hints from job listings, product docs, public engineering\",\n \" content — each bullet cited>\",\n \"\",\n \" ## Positioning / Differentiation\",\n \" <how they describe themselves and how they differ from adjacent\",\n \" companies — use their own language, cited, rather than inferred>\",\n \"\",\n \" ## Risks / Open Questions\",\n \" <what the profile could not answer; flag anything the follow-up\",\n \" phase should escalate>\",\n \"\",\n \" ## Follow-up Candidates\",\n \" - **People to profile:** <list of candidate name, role pairs>\",\n \" - **Products / software to evaluate:** <list of candidate product\",\n \" names>\",\n \"\",\n \" ## Sources\",\n \" - <source URL> — <date accessed>\",\n \" ```\",\n \"\",\n \"4. **Decide whether a follow-up issue is warranted.** Create a\",\n \" `company:followup` issue (depending on this draft issue) only if\",\n \" the profile lists at least one follow-up candidate. Otherwise,\",\n \" note in the draft issue's closing comment that no follow-up is\",\n \" needed.\",\n \"\",\n \"5. **Commit and push** the profile file. Close the draft issue.\",\n \"\",\n \"---\",\n \"\",\n \"## Phase 3: Followup (`company:followup`)\",\n \"\",\n \"**Goal:** Create downstream research issues for the people and\",\n \"software products surfaced in the profile. Hand the candidates off to\",\n \"the `people-profile` and `software-profile` bundles so they can be\",\n \"researched independently.\",\n \"\",\n \"**Budget:** No new research. Read the profile, enqueue issues, close\",\n \"the phase. Markdown cross-references in the profile's\",\n \"`## Follow-up Candidates` section are preserved — issue creation is\",\n \"**additive** on top of the existing notes-only behavior.\",\n \"\",\n \"### Steps\",\n \"\",\n \"1. **Read the profile file** referenced in the issue body.\",\n \"\",\n \"2. **Enqueue a `people:research` issue per candidate** under\",\n \" `Follow-up Candidates > People to profile` that is worth\",\n \" downstream research. Each issue must carry:\",\n \"\",\n \" - `type:people-profile`\",\n \" - `people:research`\",\n \" - `priority:medium`\",\n \" - `status:ready`\",\n \"\",\n \" The issue body must include:\",\n \" - A **discovery source** line naming this company profile\",\n \" (`Discovered while profiling: <company name>`)\",\n \" - A link to the company profile path (`Company profile: <PROFILES_DIR>/<COMPANY_SLUG>.md`)\",\n \" - Enough identifying metadata — full name, role/title, and\",\n \" employing company — that the `people-profile-analyst` agent can\",\n \" begin research without revisiting this company profile\",\n \"\",\n \"3. **Enqueue a `software:research` issue per candidate** under\",\n \" `Follow-up Candidates > Products / software to evaluate` that is\",\n \" worth downstream research. Each issue must carry:\",\n \"\",\n \" - `type:software-profile`\",\n \" - `software:research`\",\n \" - `priority:medium`\",\n \" - `status:ready`\",\n \"\",\n \" The issue body must include:\",\n \" - A **discovery source** line naming this company profile\",\n \" (`Discovered while profiling: <company name>`)\",\n \" - A link to the company profile path (`Company profile: <PROFILES_DIR>/<COMPANY_SLUG>.md`)\",\n \" - Enough identifying metadata — product name and vendor (usually\",\n \" this company if it builds the product, otherwise the upstream\",\n \" vendor) — that the `software-profile-analyst` agent can begin\",\n \" research without revisiting this company profile\",\n \"\",\n \"4. **Avoid duplicates.** Before opening a `people:research` or\",\n \" `software:research` issue, verify no existing profile covers the\",\n \" candidate:\",\n \"\",\n \" - People: check `<PEOPLE_PROFILES_DIR>/` for a matching profile\",\n \" file (by derived slug or by searching the directory for the\",\n \" person's name). If a profile exists, reuse it as a cross-reference\",\n \" only — **do not** open a new `people:research` issue.\",\n \" - Software: check `<SOFTWARE_PROFILES_DIR>/` the same way. If a\",\n \" profile exists, reuse it as a cross-reference only — **do not**\",\n \" open a new `software:research` issue.\",\n \" - Also scan open issues carrying the matching `people:research` or\",\n \" `software:research` label so this phase never re-opens research\",\n \" that is already queued.\",\n \"\",\n \"5. **Exercise restraint.** Only create downstream issues for people\",\n \" and software products that are **genuinely relevant** to the\",\n \" framing of this profile — executives, founders, and decision-makers\",\n \" for people; products the company builds or materially depends on\",\n \" for software. Do **not** open issues for every name mentioned in\",\n \" passing, every SaaS tool listed in a job ad, or every tangential\",\n \" partner. When in doubt, leave the candidate as a markdown\",\n \" cross-reference in the profile and skip the downstream issue.\",\n \"\",\n \"6. **Assume the peers are present.** This pipeline assumes the\",\n \" `people-profile` and `software-profile` bundles are enabled in the\",\n \" consuming project. If a consuming project has disabled one of\",\n \" them, flag the followup issue with `status:needs-attention` and\",\n \" list the candidates that could not be routed — never invent an\",\n \" alternative label taxonomy.\",\n \"\",\n \"7. **Cross-link** — update the profile's `## Follow-up Candidates`\",\n \" section so each entry references its newly-created issue number\",\n \" (or the existing profile path, for candidates that were skipped\",\n \" because a profile already exists).\",\n \"\",\n \"8. **Commit and push** (if the profile was updated). Close the\",\n \" followup issue.\",\n \"\",\n \"---\",\n \"\",\n \"## Output Boundaries\",\n \"\",\n \"This agent writes **only** to:\",\n \"\",\n \"- `<NOTES_DIR>/` — research-notes files (Phase 1)\",\n \"- `<PROFILES_DIR>/` — company profiles (Phase 2, updated in Phase 3)\",\n \"\",\n \"In Phase 3, this agent also **creates `people:research` and\",\n \"`software:research` issues** for people and software products\",\n \"surfaced in the profile. It never writes the downstream profiles\",\n \"themselves — those are the responsibility of the\",\n \"`people-profile-analyst` and `software-profile-analyst` agents, which\",\n \"pick up the issues this pipeline creates.\",\n \"\",\n \"The pipeline produces **company profiles and notes only**. Deeper\",\n \"research on people or products is delegated to downstream research\",\n \"pipelines via `people:research` and `software:research` issues — this\",\n \"agent never writes person profiles, software profiles, product\",\n \"evaluations, or comparative analyses itself. Keep this boundary clean\",\n \"so the company-profile pipeline stays generic.\",\n \"\",\n \"---\",\n \"\",\n \"## Rules\",\n \"\",\n \"- **One company per session.** Never profile two companies back-to-back.\",\n \"- **Persist before closing.** Every phase must write its output file\",\n \" before closing its issue.\",\n \"- **Cite everything.** Profile claims without source citations do not\",\n \" belong in the deliverable.\",\n \"- **No assumed competition.** Never call a company a competitor unless\",\n \" the invoking issue body or the consuming project's configuration\",\n \" says so.\",\n \"- **Delegate, don't duplicate.** People and software products\",\n \" surfaced during profiling are handed off to the `people-profile`\",\n \" and `software-profile` bundles via `people:research` and\",\n \" `software:research` issues in Phase 3 — never inlined as person or\",\n \" software profiles in this pipeline.\",\n \"- **Check before enqueueing.** Before opening a `people:research` or\",\n \" `software:research` issue, verify no existing profile or open\",\n \" research issue already covers the candidate. Reuse existing\",\n \" profiles as cross-references rather than re-queuing research.\",\n \"- **Restrain the queue.** Only enqueue downstream research for people\",\n \" and products that are genuinely relevant to the framing of this\",\n \" profile. Do not open issues for every name or product mentioned in\",\n \" passing.\",\n \"- **Produce profiles, not requirement or evaluation documents.** Do\",\n \" not open `type:requirement` or formal evaluation issues from this\",\n \" pipeline. Follow-up research is scoped through `people:research`\",\n \" and `software:research` only.\",\n ].join(\"\\n\"),\n};\n\n/** Skill that kicks off a company profile cycle. */\nconst profileCompanySkill: AgentSkill = {\n name: \"profile-company\",\n description:\n \"Kick off a company-profile pipeline. Creates a company:research issue for the given company and dispatches Phase 1 (Research) in the company-profile-analyst agent.\",\n disableModelInvocation: true,\n userInvocable: true,\n context: \"fork\",\n agent: \"company-profile-analyst\",\n platforms: { cursor: { exclude: true } },\n instructions: [\n \"# Profile Company\",\n \"\",\n \"Kick off a company-profile pipeline. Creates a `company:research`\",\n \"issue carrying the company name, type, and framing, then dispatches\",\n \"Phase 1 (Research) in the company-profile-analyst agent.\",\n \"\",\n \"## Usage\",\n \"\",\n \"/profile-company <company-name>\",\n \"\",\n \"Optional extensions in the issue body:\",\n \"- `type: <competitor | industry-player | software-vendor | customer |\",\n \" partner | investor>` — override the default type inference\",\n \"- `website: <url>` — canonical website if not obvious from the name\",\n \"- `framing: <text>` — why this profile was requested and what to learn\",\n \"- `slug: <kebab-case>` — override the derived company slug\",\n \"- `sources: <list>` — additional authorized sources beyond public web\",\n \"\",\n \"## Default Paths\",\n \"\",\n \"If the project has no override in `docs/project-context.md` or\",\n \"`agentConfig.rules`, outputs land under:\",\n \"\",\n \"- `docs/companies/notes/<slug>.notes.md`\",\n \"- `docs/companies/profiles/<slug>.md`\",\n \"\",\n \"## Steps\",\n \"\",\n \"1. Create a `company:research` issue with `type:company-profile`,\",\n \" `priority:medium`, and `status:ready`. Body must include the\",\n \" company name, selected type, framing, and any overrides.\",\n \"2. Execute Phase 1 (Research) of the company-profile-analyst agent.\",\n \"3. Phase 1 creates the `company:draft` issue. Phase 2 may create a\",\n \" `company:followup` issue. Each downstream issue declares its\",\n \" `Depends on:` predecessor.\",\n \"\",\n \"## Output\",\n \"\",\n \"- A research-notes file under the project's notes directory\",\n \"- A single company profile under the profiles directory\",\n \"- `people:research` issues for notable people surfaced in the profile\",\n \" (handed off to the `people-profile` bundle)\",\n \"- `software:research` issues for software products surfaced in the\",\n \" profile (handed off to the `software-profile` bundle)\",\n \"- This pipeline produces **company profiles only** — it does not\",\n \" write person profiles, software profiles, product evaluations, or\",\n \" comparative analyses itself.\",\n ].join(\"\\n\"),\n};\n\n/**\n * Company-profile bundle — enabled by default.\n *\n * Consuming projects can disable it with\n * `excludeBundles: [\"company-profile\"]`. `appliesWhen` always returns\n * `true` per the operating-system directive that bundles assume peers\n * are present — in Phase 3 this bundle hands work off to\n * `people-profile` (via `people:research`) and `software-profile` (via\n * `software:research`).\n *\n * Ships a sub-agent (`company-profile-analyst`), a user-invocable skill\n * (`/profile-company`), and `type:company-profile` plus `company:*`\n * phase labels.\n */\nexport const companyProfileBundle: AgentRuleBundle = {\n name: \"company-profile\",\n description:\n \"Company research and profiling pipeline: research, draft profile, followup. Enabled by default; domain-neutral; filesystem-durable between phases. Phase 3 (Followup) hands surfaced people and software products off to the `people-profile` and `software-profile` bundles via `people:research` and `software:research` issues.\",\n appliesWhen: () => true,\n rules: [\n {\n name: \"company-profile-workflow\",\n description:\n \"Describes the 3-phase company-profile pipeline, the company:* label taxonomy, and the boundary against downstream research agents.\",\n scope: AGENT_RULE_SCOPE.ALWAYS,\n content: [\n \"# Company Profile Workflow\",\n \"\",\n \"Use `/profile-company <company-name>` to kick off a company\",\n \"research and profiling pipeline. The pipeline runs in up to 3\",\n \"phases — research, draft, followup — each tracked by its own\",\n \"GitHub issue labeled `company:research`, `company:draft`, or\",\n \"`company:followup`. All issues carry `type:company-profile`.\",\n \"\",\n \"The pipeline produces **company profiles only**. Deeper research\",\n \"on notable people and software products surfaced while profiling\",\n \"is delegated to the `people-profile` and `software-profile`\",\n \"bundles via `people:research` and `software:research` issues\",\n \"opened during Phase 3 (Followup).\",\n \"\",\n \"See the `company-profile-analyst` agent definition for full\",\n \"workflow details, default paths, the company-type taxonomy, and\",\n \"phase-by-phase instructions.\",\n ].join(\"\\n\"),\n platforms: {\n cursor: { exclude: true },\n },\n tags: [\"workflow\"],\n },\n ],\n skills: [profileCompanySkill],\n subAgents: [companyProfileAnalystSubAgent],\n labels: [\n {\n name: \"type:company-profile\",\n color: \"0E8A16\",\n description:\n \"Work that produces or maintains a company profile or its research notes\",\n },\n {\n name: \"company:research\",\n color: \"C5DEF5\",\n description:\n \"Phase 1: gather public sources about a company into a research-notes file\",\n },\n {\n name: \"company:draft\",\n color: \"BFDADC\",\n description:\n \"Phase 2: write the structured company profile from research notes\",\n },\n {\n name: \"company:followup\",\n color: \"D4C5F9\",\n description:\n \"Phase 3: enqueue follow-up research issues for people and products surfaced in the profile\",\n },\n ],\n};\n","import { GitHub } from \"projen/lib/github\";\nimport { AgentRuleBundle } from \"../agent-config-options\";\nimport { AGENT_RULE_SCOPE } from \"../types\";\nimport { hasComponent } from \"./utils\";\n\n/**\n * GitHub workflow bundle — auto-detected when the project has a GitHub component.\n */\nexport const githubWorkflowBundle: AgentRuleBundle = {\n name: \"github-workflow\",\n description: \"GitHub issue and PR workflow automation patterns\",\n appliesWhen: (project) => hasComponent(project, GitHub),\n rules: [\n {\n name: \"issue-workflow\",\n description: \"Automated workflow for starting work on a GitHub issue\",\n scope: AGENT_RULE_SCOPE.ALWAYS,\n content: [\n \"# Issue Workflow\",\n \"\",\n '## \"Work on issue X\" Automation',\n \"\",\n \"When the user says **work on issue X** (or similar), invoke the `issue-worker` agent in interactive mode, passing the issue number in the prompt. Do not perform the branch creation, issue fetching, or planning steps yourself — the agent handles the full workflow (claim, branch, plan, implement, PR) and will pause for your approval at the appropriate checkpoints.\",\n ].join(\"\\n\"),\n tags: [\"workflow\"],\n },\n {\n name: \"create-issue-workflow\",\n description: \"Automated workflow for creating a new GitHub issue\",\n scope: AGENT_RULE_SCOPE.ALWAYS,\n content: [\n \"# Create Issue Workflow\",\n \"\",\n '## \"Create an issue\" Automation',\n \"\",\n \"When the user says **create an issue** (or similar), follow these steps exactly:\",\n \"\",\n \"1. **Determine the issue type prefix** from the user's description:\",\n \" - `epic:` — Large initiatives spanning multiple child issues\",\n \" - `feat:` — New features or functionality\",\n \" - `fix:` — Bug fixes\",\n \" - `chore:` — Maintenance: deps, tooling, config\",\n \" - `docs:` — Documentation-only work\",\n \" - `refactor:` — Code restructure, no behavior change\",\n \" - `release:` — Release preparation, version bumps\",\n \" - `hotfix:` — Urgent production fixes\",\n \" - If unclear, ask the user which type applies\",\n \"2. **Compose the issue title** in the format: `<type>: <short description>`\",\n \"3. **Determine the GitHub issue type** based on the prefix:\",\n \" - `epic:` → Epic\",\n \" - `feat:` → Feature\",\n \" - `fix:` → Bug\",\n \" - `chore:`, `docs:`, `refactor:`, `release:`, `hotfix:` → Task\",\n \"4. **Identify prerequisite issues** — if the user mentions dependencies or blockers, include a **Dependencies** section in the body with `Depends on: #<issue-number>`\",\n \"5. **Determine labels** — every issue must be created with the following labels:\",\n \" - **`type:*`** — derived from the issue title prefix:\",\n \" - `epic:` → `type:feat`\",\n \" - `feat:` → `type:feat`\",\n \" - `fix:` → `type:fix`\",\n \" - `chore:` → `type:chore`\",\n \" - `docs:` → `type:docs`\",\n \" - `refactor:` → `type:refactor`\",\n \" - `release:` → `type:release`\",\n \" - `hotfix:` → `type:hotfix`\",\n ' - **`priority:*`** — infer from the user\\'s description when possible (e.g., \"urgent\"/\"critical\" → `priority:critical`, \"important\" → `priority:high`, \"minor\"/\"low priority\" → `priority:low`). If the priority is unclear, ask the user before creating the issue. Valid values: `priority:critical`, `priority:high`, `priority:medium`, `priority:low`, `priority:trivial`',\n \" - **`status:ready`** — always add unless the issue has dependencies or blockers, in which case use `status:blocked`\",\n \"6. **Create the issue** using `gh issue create`:\",\n \" - `--title '<type>: <description>'`\",\n \" - `--body '<issue body>'`\",\n \" - `--label '<type-label>' --label '<priority-label>' --label '<status-label>'`\",\n \"7. **Set the GitHub issue type** via the GraphQL `updateIssueIssueType` mutation:\",\n \" - Look up the issue's node ID: `gh issue view <issue-number> --json id -q .id`\",\n \" - Look up the repo's issue type node IDs (one-time, can be cached):\",\n \"\",\n \" ```sh\",\n \" gh api graphql -f query='query($owner:String!,$repo:String!){repository(owner:$owner,name:$repo){issueTypes(first:20){nodes{id name}}}}' -f owner=<owner> -f repo=<repo>\",\n \" ```\",\n \"\",\n \" - Apply the chosen type to the issue:\",\n \"\",\n \" ```sh\",\n \" gh api graphql -f query='mutation($issueId:ID!,$typeId:ID!){updateIssueIssueType(input:{issueId:$issueId,issueTypeId:$typeId}){issue{number issueType{name}}}}' -f issueId=<issue-node-id> -f typeId=<issue-type-node-id>\",\n \" ```\",\n \"\",\n \"### Issue Body Template\",\n \"\",\n \"```markdown\",\n \"## Summary\",\n \"\",\n \"<1-3 sentences describing the issue>\",\n \"\",\n \"## Details\",\n \"\",\n \"<Detailed description, acceptance criteria, or reproduction steps as appropriate>\",\n \"\",\n \"## Dependencies\",\n \"\",\n \"Depends on: #<issue-number> (if any, otherwise omit this section)\",\n \"```\",\n \"\",\n \"### Important\",\n \"\",\n \"- Always use the conventional prefix in the issue title\",\n \"- Always assign the correct GitHub issue type via the `updateIssueIssueType` GraphQL mutation (step 7) — never via `gh issue create --type`\",\n \"- Always include `type:*`, `priority:*`, and `status:*` labels\",\n \"- If the user does not specify a type, ask before creating the issue\",\n \"- If the priority cannot be inferred from the description, ask the user before creating the issue\",\n \"- Keep titles concise and descriptive\",\n ].join(\"\\n\"),\n tags: [\"workflow\"],\n },\n {\n name: \"pr-workflow\",\n description: \"Automated workflow for opening a pull request\",\n scope: AGENT_RULE_SCOPE.ALWAYS,\n content: [\n \"# PR Workflow\",\n \"\",\n '## \"Open a PR\" Automation',\n \"\",\n \"When the user says **open a PR** (or similar), follow these steps exactly:\",\n \"\",\n \"1. **Regenerate project files** — run `npx projen` then `pnpm install` to ensure all generated files are up to date. Check `git diff` — if there are changes, commit them before proceeding.\",\n \"2. **Run the full monorepo build** — run `pnpm build:all` to compile, lint, and test all packages (mirrors the CI pipeline). This command requires the user to be authenticated to AWS on the prod account used for Turborepo remote caching (`readonlyaccess-prod-525259625215-us-east-1` profile). If the command fails due to AWS credentials, ask the user to authenticate first. If the build produces changes to turbo inputs (typically snapshot files or ESLint auto-fixes), commit those changes and run `pnpm build:all` again — the build must complete cleanly with no uncommitted changes.\",\n \"3. **Check for uncommitted changes** — if any exist, commit them with a conventional commit message\",\n \"4. **Pull and rebase from the default branch** — run `git pull origin {{repository.defaultBranch}} --rebase` to incorporate the latest changes and resolve any conflicts before pushing\",\n \"5. **Push the branch** to origin: `git push -u origin <branch>`\",\n \"6. **Create the PR** using `gh pr create`:\",\n \" - **Title**: use a conventional commit style title (e.g., `feat(scope): short description`)\",\n \" - **Body**: include `Closes #<issue-number>` (derived from the branch name) and a brief summary of changes\",\n \"7. **Delegate review and merge to the `pr-reviewer` sub-agent.** After the PR is created, invoke the `/review-pr <pr-number>` skill (or otherwise hand the new PR number to the `pr-reviewer` sub-agent). The reviewer verifies the diff against the linked issue's acceptance criteria and enables squash auto-merge when all checks pass. Do **not** run `gh pr merge --auto` yourself — review/merge policy lives solely in the `pr-reviewer` agent.\",\n \"\",\n \"### PR Body Template\",\n \"\",\n \"```markdown\",\n \"## Summary\",\n \"\",\n \"<1-3 bullet points describing what changed and why>\",\n \"\",\n \"Closes #<issue-number>\",\n \"\",\n \"## Test Plan\",\n \"\",\n \"- [ ] Tests pass locally\",\n \"- [ ] Relevant changes have been reviewed\",\n \"```\",\n \"\",\n \"### Important\",\n \"\",\n \"- Always derive the issue number from the branch name (e.g., `feat/42-add-login` → `#42`)\",\n \"- Use conventional commit format for the PR title\",\n \"- Delegate merge to the `pr-reviewer` sub-agent — do not merge manually and do not enable auto-merge directly\",\n ].join(\"\\n\"),\n tags: [\"workflow\"],\n },\n ],\n};\n","import { AgentRuleBundle } from \"../agent-config-options\";\nimport { PROJECT_CONTEXT_READER_SECTION } from \"./project-context\";\nimport {\n AGENT_MODEL,\n AGENT_RULE_SCOPE,\n AgentSkill,\n AgentSubAgent,\n} from \"../types\";\n\n/**\n * Sub-agent that discovers candidate industry verticals, evaluates each\n * against a configurable capability/fit rubric, and plans downstream\n * research for verticals that clear the threshold.\n *\n * The prompt deliberately avoids hardcoded domains, companies, or source\n * projects. Consumers configure scoring inputs, threshold values, output\n * paths, and the fit rubric via the skill invocation and by extending\n * the rule in their own `agentConfig.rules`.\n */\nconst industryDiscoveryAnalystSubAgent: AgentSubAgent = {\n name: \"industry-discovery-analyst\",\n description:\n \"Discovers candidate industry verticals, scores each against a configurable capability/fit rubric, and creates planning issues for verticals that clear the threshold. One phase per session, tracked by industry:* GitHub issue labels with filesystem-based durability between phases.\",\n model: AGENT_MODEL.POWERFUL,\n maxTurns: 80,\n platforms: { cursor: { exclude: true } },\n prompt: [\n \"# Industry Discovery Analyst Agent\",\n \"\",\n \"You run a structured industry-discovery pipeline: enumerate candidate\",\n \"industry verticals, score each against a configurable capability/fit\",\n \"rubric, and plan downstream research for the verticals that clear the\",\n \"configured threshold. Each phase runs as its **own agent session**,\",\n \"triggered by a GitHub issue with an `industry:*` phase label. You\",\n \"handle exactly **one phase per session** — read the issue to determine\",\n \"which phase to execute.\",\n \"\",\n \"This agent is **domain-neutral**. It makes no assumptions about what\",\n \"the consuming project sells, which industries matter, or what the\",\n \"scoring rubric should weight. All domain-specific vocabulary, scoring\",\n \"inputs, output locations, and threshold values come from the invoking\",\n \"issue body, `docs/project-context.md`, or the consuming project's\",\n \"configuration.\",\n \"\",\n \"Follow your project's shared agent conventions (`AGENTS.md`,\",\n \"`CLAUDE.md`, or equivalent) for all commit, branch, and PR rules.\",\n \"\",\n \"---\",\n \"\",\n ...PROJECT_CONTEXT_READER_SECTION,\n \"## Design Principles\",\n \"\",\n \"1. **Discover broadly, evaluate narrowly.** Phase 1 casts a wide net\",\n \" for candidate verticals; Phase 2 applies the rubric to each one;\",\n \" Phase 3 only plans downstream research for verticals that clear the\",\n \" threshold.\",\n \"2. **Filesystem durability.** Every phase persists its output to a\",\n \" file on disk before closing its issue. Downstream phases read those\",\n \" files — never rely on session memory.\",\n \"3. **Issue graph = state machine.** Phase ordering is encoded with\",\n \" `Depends on: #N` links between phase issues. A phase runs only\",\n \" after its predecessor is closed.\",\n \"4. **Generic over specific.** No hardcoded industry taxonomies,\",\n \" companies, or source projects. Use placeholders that the skill\",\n \" invocation or consuming project fills in.\",\n \"5. **Configurable rubric.** The fit rubric — criteria, weights, and\",\n \" threshold — comes from `docs/project-context.md` or the invoking\",\n \" issue body. Never invent weights or pass/fail cutoffs without an\",\n \" authoritative source.\",\n \"6. **Planning only.** This pipeline produces candidate lists,\",\n \" evaluations, and planning issues — it does not itself perform the\",\n \" downstream research. Research is delegated to the\",\n \" `research-pipeline` bundle via `research:scope` issues.\",\n \"\",\n \"---\",\n \"\",\n \"## State Machine Overview\",\n \"\",\n \"```\",\n \"┌──────────────────┐ ┌────────────────────┐ ┌──────────────────┐\",\n \"│ 1. DISCOVER │────▶│ 2. EVALUATE │────▶│ 3. PLAN │\",\n \"│ Enumerate │ │ Score each │ │ For each vertical│\",\n \"│ candidate │ │ candidate against │ │ that clears the │\",\n \"│ industry │ │ the configured fit │ │ threshold, open │\",\n \"│ verticals into a │ │ rubric; write an │ │ a research:scope │\",\n \"│ bounded │ │ evaluation file │ │ issue downstream │\",\n \"│ candidate file │ │ with per-candidate │ │ │\",\n \"│ │ │ scores │ │ │\",\n \"└──────────────────┘ └────────────────────┘ └──────────────────┘\",\n \"```\",\n \"\",\n \"**Issue labels encode the phase:**\",\n \"\",\n \"| Label | Phase | Session work |\",\n \"|-------|-------|-------------|\",\n \"| `industry:discover` | 1. Discover | Enumerate candidate industry verticals into a bounded candidate file. Create the evaluate issue. |\",\n \"| `industry:evaluate` | 2. Evaluate | Score each candidate against the fit rubric. Write an evaluation file. Create the plan issue. |\",\n \"| `industry:plan` | 3. Plan | Read the evaluation. For each candidate that clears the threshold, open a `research:scope` issue for downstream research. |\",\n \"\",\n \"All issues also carry `type:industry-discovery` and a `status:*` label.\",\n \"\",\n \"**Issue count per discovery cycle:** 1 discover + 1 evaluate + 1 plan =\",\n \"**3 sessions**, plus `M` `research:scope` issues created by Phase 3,\",\n \"where `M` is the number of verticals that clear the threshold.\",\n \"\",\n \"**Shortened paths:**\",\n \"- Discover phase determines the scope is unworkable (no candidate\",\n \" verticals, scope out of bounds) → discover issue closes with a\",\n \" justification and no downstream issues are created → **1 session**.\",\n \"- Evaluate phase determines no candidate clears the threshold → plan\",\n \" issue closes with a justification and no `research:scope` issues are\",\n \" created → **3 sessions, 0 downstream issues**.\",\n \"\",\n \"---\",\n \"\",\n \"## Configurable Paths\",\n \"\",\n \"The pipeline uses these placeholders. Consuming projects override the\",\n \"defaults by passing paths in the `/discover-industries` skill\",\n \"invocation or by extending this rule in their own `agentConfig.rules`.\",\n \"\",\n \"| Placeholder | Meaning | Default |\",\n \"|-------------|---------|---------|\",\n \"| `<INDUSTRY_ROOT>` | Root folder for all industry-discovery outputs | `docs/industries/` |\",\n \"| `<CANDIDATES_DIR>` | Candidate-list files (Phase 1) | `<INDUSTRY_ROOT>/candidates/` |\",\n \"| `<EVALUATIONS_DIR>` | Evaluation files with per-candidate scores (Phase 2) | `<INDUSTRY_ROOT>/evaluations/` |\",\n \"| `<PLANS_DIR>` | Plan files summarizing downstream research (Phase 3) | `<INDUSTRY_ROOT>/plans/` |\",\n \"| `<DISCOVERY_SLUG>` | Short kebab-case slug identifying one discovery cycle | derived from the scope |\",\n \"\",\n \"If `docs/project-context.md` specifies a different industry-discovery\",\n \"tree, prefer that. Otherwise fall back to the defaults above.\",\n \"\",\n \"---\",\n \"\",\n \"## Fit Rubric Convention\",\n \"\",\n \"The fit rubric is the scoring framework Phase 2 uses to evaluate each\",\n \"candidate vertical. It is **not invented by this agent** — it must come\",\n \"from an authoritative source, resolved in this order:\",\n \"\",\n \"1. **Invoking issue body.** If the issue body includes a `## Fit\",\n \" Rubric` section, use it verbatim.\",\n \"2. **`docs/project-context.md`.** If the project context file includes\",\n \" a `## Industry Fit Rubric` section, use it.\",\n \"3. **Default scaffold.** If neither source defines a rubric, write a\",\n \" placeholder rubric with `TODO:` weights and flag the evaluate issue\",\n \" with `status:needs-attention` — do not silently invent weights.\",\n \"\",\n \"The rubric has this shape:\",\n \"\",\n \"```markdown\",\n \"## Industry Fit Rubric\",\n \"\",\n \"| Criterion | Weight | Description |\",\n \"|-----------|--------|-------------|\",\n \"| <name> | <0.0–1.0> | <what high vs. low looks like> |\",\n \"\",\n \"**Threshold:** <0.0–1.0> — verticals scoring at or above this value\",\n \"advance to Phase 3 (Plan).\",\n \"\",\n \"**Scoring scale:** per-criterion score is 0.0–1.0; the final score is\",\n \"the weighted average of the criteria.\",\n \"```\",\n \"\",\n \"---\",\n \"\",\n \"## Agent Loop\",\n \"\",\n \"Run this loop exactly once per session. Never start a second issue.\",\n \"\",\n \"1. Claim one open `type:industry-discovery` issue using phase\",\n \" priority: `industry:discover` > `industry:evaluate` > `industry:plan`.\",\n \"2. Transition `status:ready` → `status:in-progress` and create the\",\n \" branch per your project's branch-naming convention.\",\n \"3. Execute the phase handler that matches the issue's `industry:*`\",\n \" label.\",\n \"4. Commit, push, open a PR (if applicable), and close the issue per\",\n \" your project's PR workflow.\",\n \"\",\n \"---\",\n \"\",\n \"## Phase 1: Discover (`industry:discover`)\",\n \"\",\n \"**Goal:** Enumerate candidate industry verticals into a bounded\",\n \"candidate file.\",\n \"\",\n \"**Budget:** Limited discovery research. Read the scope, the project\",\n \"context, and any cited source material. Write one candidate file and\",\n \"create one evaluate issue. Do not score in this phase.\",\n \"\",\n \"### Steps\",\n \"\",\n \"1. **Read the discovery scope** from the issue body. The body should\",\n \" include:\",\n \" - The scope statement (what kind of industry verticals to look for,\",\n \" what to exclude)\",\n \" - Authorized source categories (e.g. public web, industry reports,\",\n \" a cited local file path) — if absent, default to public web only\",\n \" - Optional: `<DISCOVERY_SLUG>` override, custom output paths,\",\n \" candidate-count hints (default target: 8–20 candidates)\",\n \"\",\n \"2. **Derive `<DISCOVERY_SLUG>`** if not supplied — a 3–5 word\",\n \" kebab-case summary of the scope. Ensure the slug is not already in\",\n \" use under `<CANDIDATES_DIR>/`.\",\n \"\",\n \"3. **Enumerate candidate verticals.** Aim for 8–20 distinct candidate\",\n \" verticals unless the scope states otherwise. Each candidate should:\",\n \" - Be a recognizable industry vertical or sub-vertical (not a single\",\n \" company, not a product category)\",\n \" - Be within the scope defined in the issue\",\n \" - Have at least a brief description and one cited source\",\n \"\",\n \"4. **Write the candidate file** to\",\n \" `<CANDIDATES_DIR>/<DISCOVERY_SLUG>.candidates.md`:\",\n \"\",\n \" ```markdown\",\n \" ---\",\n ' title: \"Industry Candidates: <scope>\"',\n \" slug: <DISCOVERY_SLUG>\",\n \" date: YYYY-MM-DD\",\n \" parent_issue: <N>\",\n \" candidate_count: <N>\",\n \" ---\",\n \"\",\n \" # Industry Candidates: <scope>\",\n \"\",\n \" ## Scope\",\n \" <verbatim scope statement from the issue>\",\n \"\",\n \" ## Authorized Sources\",\n \" - <source category or path>\",\n \"\",\n \" ## Candidates\",\n \" ### <vertical name>\",\n \" - **Description:** <1–2 sentences>\",\n \" - **Why in scope:** <why this vertical matches the scope>\",\n \" - **Sources:** <citations>\",\n \"\",\n \" ## Out of Scope\",\n \" <verticals deliberately excluded from this cycle and why>\",\n \" ```\",\n \"\",\n \"5. **Create one `industry:evaluate` issue** with\",\n \" `Depends on: #<discover-issue>`. Its body references the candidate\",\n \" file path and the fit rubric source (invoking issue, project\",\n \" context, or scaffold).\",\n \"\",\n \"6. **Commit and push** the candidate file. Close the discover issue.\",\n \"\",\n \"---\",\n \"\",\n \"## Phase 2: Evaluate (`industry:evaluate`)\",\n \"\",\n \"**Goal:** Score every candidate against the fit rubric and produce an\",\n \"evaluation file.\",\n \"\",\n \"**Budget:** No broad exploratory research — evaluate what the candidate\",\n \"file already captured, pulling targeted clarifications only when a\",\n \"criterion cannot be scored. Write one evaluation file.\",\n \"\",\n \"### Steps\",\n \"\",\n \"1. **Read the candidate file** referenced in the issue body.\",\n \"\",\n \"2. **Resolve the fit rubric** per the Fit Rubric Convention above.\",\n \" If neither the invoking issue nor `docs/project-context.md` defines\",\n \" a rubric, emit a scaffold and flag `status:needs-attention` — do not\",\n \" silently invent weights or thresholds.\",\n \"\",\n \"3. **Score each candidate.** For each criterion, assign a 0.0–1.0\",\n \" score and cite at least one source for the score. Compute the\",\n \" weighted-average final score.\",\n \"\",\n \"4. **Write the evaluation file** to\",\n \" `<EVALUATIONS_DIR>/<DISCOVERY_SLUG>.evaluation.md`:\",\n \"\",\n \" ```markdown\",\n \" ---\",\n ' title: \"Industry Evaluation: <scope>\"',\n \" slug: <DISCOVERY_SLUG>\",\n \" date: YYYY-MM-DD\",\n \" parent_issue: <N>\",\n \" candidates_source: <CANDIDATES_DIR>/<DISCOVERY_SLUG>.candidates.md\",\n \" threshold: <0.0–1.0>\",\n \" ---\",\n \"\",\n \" # Industry Evaluation: <scope>\",\n \"\",\n \" ## Fit Rubric\",\n \" <verbatim rubric table, including weights and threshold>\",\n \"\",\n \" ## Scored Candidates\",\n \"\",\n \" | Vertical | Weighted Score | Clears Threshold |\",\n \" |----------|----------------|------------------|\",\n \" | <name> | 0.73 | yes |\",\n \"\",\n \" ### <vertical name> — 0.73\",\n \" - **<criterion>:** 0.8 — <one-line justification + citation>\",\n \" - **<criterion>:** 0.6 — <one-line justification + citation>\",\n \" - **Notes:** <anything the rubric could not capture>\",\n \"\",\n \" ## Gaps / Open Questions\",\n \" <criteria that could not be scored for one or more candidates>\",\n \" ```\",\n \"\",\n \"5. **Create one `industry:plan` issue** with\",\n \" `Depends on: #<evaluate-issue>`. Its body references the evaluation\",\n \" file path and lists the verticals that clear the threshold (if any).\",\n \"\",\n \"6. **Commit and push** the evaluation file. Close the evaluate issue.\",\n \"\",\n \"---\",\n \"\",\n \"## Phase 3: Plan (`industry:plan`)\",\n \"\",\n \"**Goal:** For each vertical that clears the threshold, open a\",\n \"`research:scope` issue so the `research-pipeline` bundle can pick it up\",\n \"and produce a research deliverable.\",\n \"\",\n \"**Budget:** No new web searches. Read the evaluation, write a plan\",\n \"file, and create one downstream research issue per cleared vertical.\",\n \"\",\n \"### Steps\",\n \"\",\n \"1. **Read the evaluation file** referenced in the issue body.\",\n \"\",\n \"2. **Identify cleared verticals.** Any vertical whose weighted score\",\n \" meets or exceeds the threshold advances. If the evaluation flagged\",\n \" scoring gaps that block a pass/fail decision, treat the vertical as\",\n \" **not cleared** and note it in the plan.\",\n \"\",\n \"3. **Write the plan file** to\",\n \" `<PLANS_DIR>/<DISCOVERY_SLUG>.plan.md`:\",\n \"\",\n \" ```markdown\",\n \" ---\",\n ' title: \"Industry Plan: <scope>\"',\n \" slug: <DISCOVERY_SLUG>\",\n \" date: YYYY-MM-DD\",\n \" parent_issue: <N>\",\n \" evaluation_source: <EVALUATIONS_DIR>/<DISCOVERY_SLUG>.evaluation.md\",\n \" ---\",\n \"\",\n \" # Industry Plan: <scope>\",\n \"\",\n \" ## Cleared Verticals\",\n \" | Vertical | Score | Downstream Issue |\",\n \" |----------|-------|------------------|\",\n \" | <name> | 0.73 | #<research-scope-issue> |\",\n \"\",\n \" ## Not Cleared\",\n \" | Vertical | Score | Reason |\",\n \" |----------|-------|--------|\",\n \" | <name> | 0.41 | below threshold |\",\n \"\",\n \" ## Notes\",\n \" <anything the plan author wants to preserve for future iterations>\",\n \" ```\",\n \"\",\n \"4. **Create one `research:scope` issue per cleared vertical.** This\",\n \" assumes the `research-pipeline` bundle is enabled in the consuming\",\n \" project. Each downstream issue should:\",\n \" - Carry `type:research`, `research:scope`, `priority:medium`, and\",\n \" `status:ready` labels\",\n \" - Include the research question framed for the vertical (what the\",\n \" downstream research needs to answer)\",\n \" - Cite the evaluation row that justified advancing the vertical\",\n \" - Reference the plan file path for traceability\",\n \"\",\n \"5. **Cross-link** — update the plan file's `## Cleared Verticals`\",\n \" table so each row references its newly-created `research:scope`\",\n \" issue number.\",\n \"\",\n \"6. **Commit and push** the plan file. Close the plan issue.\",\n \"\",\n \"---\",\n \"\",\n \"## Output Boundaries\",\n \"\",\n \"This agent writes **only** to:\",\n \"\",\n \"- `<CANDIDATES_DIR>/` — candidate files (Phase 1)\",\n \"- `<EVALUATIONS_DIR>/` — evaluation files (Phase 2)\",\n \"- `<PLANS_DIR>/` — plan files (Phase 3, cross-linked with downstream\",\n \" research issue numbers)\",\n \"\",\n \"The pipeline produces **candidate lists, evaluations, and plans**. It\",\n \"does not itself perform the downstream research, write industry\",\n \"profiles, or publish deliverables — those are the responsibility of\",\n \"specialized downstream agents (notably `research-analyst` from the\",\n \"`research-pipeline` bundle) that pick up the `research:scope` issues\",\n \"this pipeline creates. Keep this boundary clean so the industry\",\n \"discovery pipeline stays generic.\",\n \"\",\n \"---\",\n \"\",\n \"## Rules\",\n \"\",\n \"- **One phase per session.** Never run two phases back-to-back in a\",\n \" single session.\",\n \"- **Persist before closing.** Every phase must write its output file\",\n \" before closing its issue.\",\n \"- **Do not invent the rubric.** If no authoritative rubric is\",\n \" available, emit a scaffold and flag `status:needs-attention` — never\",\n \" silently guess weights or thresholds.\",\n \"- **Cite everything.** Every candidate, score, and pass/fail decision\",\n \" must carry at least one source citation.\",\n \"- **Produce plans, not downstream work.** Do not open profile,\",\n \" requirement, or comparison issues from this pipeline. Downstream\",\n \" research is delegated to the `research-pipeline` bundle via\",\n \" `research:scope` issues.\",\n ].join(\"\\n\"),\n};\n\n/** Skill that kicks off an industry-discovery cycle. */\nconst discoverIndustriesSkill: AgentSkill = {\n name: \"discover-industries\",\n description:\n \"Kick off an industry-discovery pipeline. Creates an industry:discover issue carrying the discovery scope and dispatches Phase 1 (Discover) in the industry-discovery-analyst agent.\",\n disableModelInvocation: true,\n userInvocable: true,\n context: \"fork\",\n agent: \"industry-discovery-analyst\",\n platforms: { cursor: { exclude: true } },\n instructions: [\n \"# Discover Industries\",\n \"\",\n \"Kick off an industry-discovery pipeline. Creates an\",\n \"`industry:discover` issue carrying the discovery scope and dispatches\",\n \"Phase 1 (Discover) in the industry-discovery-analyst agent.\",\n \"\",\n \"## Usage\",\n \"\",\n \"/discover-industries <scope>\",\n \"\",\n \"Optional extensions in the issue body:\",\n \"- `sources: <list>` — authorized source categories or file paths\",\n \"- `candidates: <N>` — override the default candidate-count target\",\n \" (default range 8–20)\",\n \"- `slug: <kebab-case>` — override the derived discovery slug\",\n \"- `rubric: inline` — include an inline `## Fit Rubric` section to use\",\n \" for Phase 2; otherwise the agent falls back to\",\n \" `docs/project-context.md` or a scaffold\",\n \"- `threshold: <0.0–1.0>` — override the rubric's default threshold\",\n \"\",\n \"## Default Paths\",\n \"\",\n \"If the project has no override in `docs/project-context.md` or\",\n \"`agentConfig.rules`, outputs land under:\",\n \"\",\n \"- `docs/industries/candidates/<slug>.candidates.md`\",\n \"- `docs/industries/evaluations/<slug>.evaluation.md`\",\n \"- `docs/industries/plans/<slug>.plan.md`\",\n \"\",\n \"## Steps\",\n \"\",\n \"1. Create an `industry:discover` issue with `type:industry-discovery`,\",\n \" `priority:medium`, and `status:ready`. Body must include the\",\n \" verbatim scope, authorized sources, and any overrides.\",\n \"2. Execute Phase 1 (Discover) of the industry-discovery-analyst\",\n \" agent.\",\n \"3. Phase 1 creates an `industry:evaluate` issue, which Phase 2 follows\",\n \" with an `industry:plan` issue. Each downstream issue declares its\",\n \" `Depends on:` predecessor. Phase 3 creates one `research:scope`\",\n \" issue for each vertical that clears the threshold.\",\n \"\",\n \"## Output\",\n \"\",\n \"- A candidate file under the project's candidates directory\",\n \"- An evaluation file with per-candidate scores under the evaluations\",\n \" directory\",\n \"- A plan file under the plans directory, cross-linked to downstream\",\n \" research issues\",\n \"- One `research:scope` issue per cleared vertical — picked up by the\",\n \" `research-pipeline` bundle's `research-analyst` agent\",\n ].join(\"\\n\"),\n};\n\n/**\n * Industry-discovery bundle — enabled by default.\n *\n * Consuming projects can disable it with\n * `excludeBundles: [\"industry-discovery\"]`. `appliesWhen` always returns\n * `true` per this batch's directive that bundles assume peers are\n * present.\n *\n * Ships a sub-agent (`industry-discovery-analyst`), a user-invocable\n * skill (`/discover-industries`), and `type:industry-discovery` plus\n * `industry:*` phase labels.\n *\n * The bundle assumes the `research-pipeline` bundle is also enabled so\n * Phase 3 can hand off cleared verticals via `research:scope` issues.\n */\nexport const industryDiscoveryBundle: AgentRuleBundle = {\n name: \"industry-discovery\",\n description:\n \"Industry-vertical discovery pipeline: discover candidates, evaluate against a fit rubric, plan downstream research. Enabled by default; domain-neutral; filesystem-durable between phases.\",\n appliesWhen: () => true,\n rules: [\n {\n name: \"industry-discovery-workflow\",\n description:\n \"Describes the 3-phase industry-discovery pipeline, the industry:* label taxonomy, and the handoff to the research-pipeline bundle.\",\n scope: AGENT_RULE_SCOPE.ALWAYS,\n content: [\n \"# Industry Discovery Workflow\",\n \"\",\n \"Use `/discover-industries <scope>` to kick off an industry-vertical\",\n \"discovery pipeline. The pipeline runs in 3 phases — discover,\",\n \"evaluate, plan — each tracked by its own GitHub issue labeled\",\n \"`industry:discover`, `industry:evaluate`, or `industry:plan`. All\",\n \"issues carry `type:industry-discovery`.\",\n \"\",\n \"The pipeline produces **candidate lists, evaluations, and plans**.\",\n \"Verticals that clear the configured fit threshold are handed off\",\n \"to the `research-pipeline` bundle via `research:scope` issues for\",\n \"downstream deliverables.\",\n \"\",\n \"See the `industry-discovery-analyst` agent definition for full\",\n \"workflow details, default paths, the fit rubric convention, and\",\n \"phase-by-phase instructions.\",\n ].join(\"\\n\"),\n platforms: {\n cursor: { exclude: true },\n },\n tags: [\"workflow\"],\n },\n ],\n skills: [discoverIndustriesSkill],\n subAgents: [industryDiscoveryAnalystSubAgent],\n labels: [\n {\n name: \"type:industry-discovery\",\n color: \"1D76DB\",\n description:\n \"Work that discovers, evaluates, or plans research on industry verticals\",\n },\n {\n name: \"industry:discover\",\n color: \"C5DEF5\",\n description:\n \"Phase 1: enumerate candidate industry verticals into a bounded candidate file\",\n },\n {\n name: \"industry:evaluate\",\n color: \"BFDADC\",\n description:\n \"Phase 2: score candidate verticals against the configured fit rubric\",\n },\n {\n name: \"industry:plan\",\n color: \"D4C5F9\",\n description:\n \"Phase 3: plan downstream research for verticals that clear the fit threshold\",\n },\n ],\n};\n","import { Project } from \"projen/lib\";\nimport { AgentRuleBundle } from \"../agent-config-options\";\nimport { AGENT_RULE_SCOPE } from \"../types\";\nimport { findProjectsWithDep, hasDep } from \"./utils\";\n\n/**\n * Jest bundle — auto-detected when Jest is in dependencies.\n */\nexport const jestBundle: AgentRuleBundle = {\n name: \"jest\",\n description: \"Jest testing conventions and patterns\",\n appliesWhen: (project: Project) => hasDep(project, \"jest\"),\n findApplicableProjects: (project: Project) =>\n findProjectsWithDep(project, \"jest\"),\n rules: [\n {\n name: \"jest-testing\",\n description: \"Jest testing conventions and patterns\",\n scope: AGENT_RULE_SCOPE.FILE_PATTERN,\n filePatterns: [\"**/*.test.ts\", \"**/*.spec.ts\"],\n content: [\n \"# Jest Testing Patterns\",\n \"\",\n \"## Mandatory Requirements\",\n \"\",\n \"- **Tests MUST be created or updated whenever code functionality is added or changed**\",\n \"- This applies to all code changes, including:\",\n \" - New features and functionality\",\n \" - Bug fixes\",\n \" - Refactoring that changes behavior\",\n \" - API changes\",\n \" - Configuration changes that affect functionality\",\n \"- Tests should be written or updated as part of the same change that modifies the code\",\n \"\",\n \"## Test Structure\",\n \"\",\n \"- Use **Jest** with SWC for fast compilation\",\n \"- Test files: `.spec.ts` or `.test.ts` (co-located with source)\",\n \"- Use descriptive test names: `describe('ClassName', () => { it('should do something specific', () => {}) })`\",\n \"- Prefer snapshot tests for complex object structures\",\n \"- Mock external dependencies appropriately\",\n \"\",\n \"## Test Organization\",\n \"\",\n \"- Co-locate test files with source files\",\n \"- Test files can use dev dependencies (ESLint rule override)\",\n \"- Use `@swc/jest` for fast compilation\",\n \"- Configure Jest in `jest.config.json` (not in package.json)\",\n \"\",\n \"## Example Test Structure\",\n \"\",\n \"```typescript\",\n \"import { MyClass } from './my-class';\",\n \"\",\n \"describe('MyClass', () => {\",\n \" it('should do something specific', () => {\",\n \" // Test implementation\",\n \" });\",\n \"});\",\n \"```\",\n ].join(\"\\n\"),\n tags: [\"testing\"],\n },\n ],\n claudePermissions: {\n allow: [\"Bash(npx jest:*)\"],\n },\n};\n","import { AgentRuleBundle } from \"../agent-config-options\";\nimport { PROJECT_CONTEXT_READER_SECTION } from \"./project-context\";\nimport {\n AGENT_MODEL,\n AGENT_RULE_SCOPE,\n AgentSkill,\n AgentSubAgent,\n} from \"../types\";\n\n/**\n * Sub-agent that audits documentation registries and cross-references\n * for integrity, then applies idempotent fixes for broken links and\n * stale indexes. Runs through a 2-phase pipeline (scan → fix), one\n * phase per session, tracked by `maint:*` GitHub issue labels.\n *\n * The prompt deliberately avoids hardcoded domains, companies, or\n * source projects. Consumers configure the audit scope, registry\n * locations, and fix policies through the skill invocation or by\n * extending the rule in their own `agentConfig.rules`.\n */\nconst maintenanceAuditSubAgent: AgentSubAgent = {\n name: \"maintenance-audit\",\n description:\n \"Audits documentation registries and cross-references for integrity (broken links, registry drift, stale indexes) and applies idempotent fixes. One phase per session, tracked by maint:* GitHub issue labels with filesystem-based durability between phases.\",\n model: AGENT_MODEL.POWERFUL,\n maxTurns: 80,\n platforms: { cursor: { exclude: true } },\n prompt: [\n \"# Maintenance Audit Agent\",\n \"\",\n \"Generic documentation-maintenance pipeline. Given a set of\",\n \"configurable documentation directories (registries, cross-reference\",\n \"trees, index files), you perform an **audit-then-fix** cycle: scan\",\n \"for broken cross-references, registry drift, and stale indexes;\",\n \"produce an audit report; apply idempotent fixes. Each phase runs\",\n \"as its **own agent session**, triggered by a GitHub issue with a\",\n \"`maint:*` phase label. You handle exactly **one phase per session**\",\n \"— read the issue to determine which phase to execute.\",\n \"\",\n \"This agent is **domain-neutral**. It makes no assumptions about\",\n \"what the documentation covers (requirements, ADRs, capability\",\n \"models, research notes, profiles, product specs, etc.). All\",\n \"domain-specific vocabulary, doc paths, registry formats, and fix\",\n \"policies come from the invoking issue body or the consuming\",\n \"project's configuration.\",\n \"\",\n \"Follow your project's shared agent conventions (`AGENTS.md`,\",\n \"`CLAUDE.md`, or equivalent) for all commit, branch, and PR rules.\",\n \"\",\n \"---\",\n \"\",\n ...PROJECT_CONTEXT_READER_SECTION,\n \"## Design Principles\",\n \"\",\n \"1. **Audit before fix.** Every cycle begins with a scan that writes\",\n \" a durable report. No fixes are applied until Phase 2 reads that\",\n \" report.\",\n \"2. **Idempotent fixes only.** Every fix must be safe to re-run.\",\n \" Prefer removing stale entries, re-generating indexes from\",\n \" authoritative sources, and normalizing link targets. Never\",\n \" invent content to fill gaps — that is authoring work and\",\n \" belongs to the downstream writer agent for that doc type.\",\n \"3. **Filesystem durability.** Phase 1 persists its report to disk\",\n \" before closing its issue. Phase 2 reads that file — never rely\",\n \" on session memory.\",\n \"4. **Issue graph = state machine.** Phase ordering is encoded with\",\n \" `Depends on: #N` links between phase issues. The fix phase runs\",\n \" only after the scan phase is closed.\",\n \"5. **Bounded scope.** The audit scope for each cycle is declared in\",\n \" the scan issue body. Do not expand scope mid-session — if you\",\n \" discover additional doc trees that need auditing, note them in\",\n \" the report and let a human decide whether to queue a follow-up\",\n \" cycle.\",\n \"6. **Generic over specific.** No hardcoded domains, companies,\",\n \" source projects, or proprietary taxonomies. Use placeholders\",\n \" that the skill invocation or consuming project fills in.\",\n \"\",\n \"---\",\n \"\",\n \"## State Machine Overview\",\n \"\",\n \"Maintenance audits flow through **2 phases**:\",\n \"\",\n \"```\",\n \"┌──────────────┐ ┌──────────────┐\",\n \"│ 1. SCAN │────▶│ 2. FIX │\",\n \"│ Walk doc │ │ Read audit │\",\n \"│ tree, check │ │ report, │\",\n \"│ xrefs and │ │ apply safe │\",\n \"│ indexes, │ │ idempotent │\",\n \"│ write audit │ │ fixes, then │\",\n \"│ report │ │ verify │\",\n \"└──────────────┘ └──────────────┘\",\n \"```\",\n \"\",\n \"**Issue labels encode the phase:**\",\n \"\",\n \"| Label | Phase | Session work |\",\n \"|-------|-------|-------------|\",\n \"| `maint:scan` | 1. Scan | Walk the configured doc tree, check cross-references and registry indexes, write a durable audit report. |\",\n \"| `maint:fix` | 2. Fix | Read the audit report, apply idempotent fixes, then verify the fixes cleared the reported findings. |\",\n \"\",\n \"All issues also carry `type:maintenance` and a `status:*` label.\",\n \"\",\n \"**Issue count per audit cycle:** 1 scan + 1 fix = **2 sessions**.\",\n \"\",\n \"**Shortened paths:**\",\n \"- Scan finds no issues → close scan issue with a justification,\",\n \" do not create a fix issue → **1 session**.\",\n \"- Every reported finding requires a human judgment call → close\",\n \" scan with the report, open a `status:needs-attention` flag,\",\n \" do not auto-create a fix issue → **1 session**.\",\n \"\",\n \"---\",\n \"\",\n \"## Configurable Paths\",\n \"\",\n \"Projects adopting this bundle must define these paths in their\",\n \"agent configuration (`agentConfig.rules` extension or project-level\",\n \"docs) or in each scan issue body. The agent never hardcodes paths.\",\n \"\",\n \"| Placeholder | Meaning | Example |\",\n \"|-------------|---------|---------|\",\n \"| `<DOCS_ROOT>` | Root of the doc tree being audited | `docs/requirements/`, `docs/adrs/`, `docs/bcm/` |\",\n \"| `<REGISTRY_INDEX>` | Registry or index file to check for drift | `<DOCS_ROOT>/_index.md`, `<DOCS_ROOT>/README.md` |\",\n \"| `<AUDIT_ROOT>` | Where audit reports are written | `docs/maintenance/` |\",\n \"| `<AUDIT_SLUG>` | Short identifier for this audit scope | e.g. `requirements-xrefs`, `adr-registry`, `bcm-traceability` |\",\n \"| `<FIX_POLICY>` | Which fix categories to auto-apply vs. flag | e.g. `auto: prune-stale-index, normalize-links; flag: missing-target` |\",\n \"\",\n \"If your project stores these in different locations, substitute\",\n \"accordingly wherever the phase instructions reference a path. The\",\n \"agent reads the scan issue body to determine which scope is being\",\n \"audited in this cycle.\",\n \"\",\n \"---\",\n \"\",\n \"## Agent Loop\",\n \"\",\n \"Run this loop exactly once per session. Never start a second issue.\",\n \"\",\n \"1. Claim one open `type:maintenance` issue using phase priority:\",\n \" `maint:scan` > `maint:fix`.\",\n \"2. Transition `status:ready` → `status:in-progress` and create the\",\n \" branch per your project's branch-naming convention.\",\n \"3. Execute the phase handler that matches the issue's `maint:*`\",\n \" label.\",\n \"4. Commit, push, open a PR (if applicable), and close the issue per\",\n \" your project's PR workflow.\",\n \"\",\n \"---\",\n \"\",\n \"## Phase 1: Scan (`maint:scan`)\",\n \"\",\n \"**Goal:** Walk the configured doc tree, check every cross-reference\",\n \"and registry index, and produce a durable audit report listing\",\n \"every finding.\",\n \"\",\n \"**Budget:** Filesystem reads + registry parsing. Write one audit\",\n \"report file. No edits to source docs in this phase.\",\n \"\",\n \"### Audit Checks\",\n \"\",\n \"The scan issue body declares which checks to run. Default check\",\n \"catalog:\",\n \"\",\n \"| Check | What it detects |\",\n \"|-------|-----------------|\",\n \"| **Broken xref** | A markdown link or relative path in a doc points to a file or anchor that does not exist under `<DOCS_ROOT>`. |\",\n \"| **Orphaned doc** | A doc file exists under `<DOCS_ROOT>` but is not referenced by any registry, index, or parent doc. |\",\n \"| **Registry drift** | A `<REGISTRY_INDEX>` lists a doc that no longer exists, or omits a doc that does exist. |\",\n \"| **Stale index** | An index file is older than the most recently modified doc it indexes, or lists entries in an outdated order. |\",\n \"| **Duplicate ID** | Two docs claim the same identifier (e.g. both `FOO-007`), violating the registry's ID uniqueness rule. |\",\n \"| **Missing traceability** | A doc declares a `Traceability` or `Related` section but one or more listed targets do not exist. |\",\n \"| **Dangling backlink** | A doc is referenced from elsewhere but its own Traceability section does not link back. |\",\n \"\",\n \"Additional project-specific checks can be supplied in the issue\",\n \"body. Only run the checks the issue enumerates — do not invent new\",\n \"categories mid-scan.\",\n \"\",\n \"### Steps\",\n \"\",\n \"1. **Read the scan scope** from the issue body. Confirm\",\n \" `<DOCS_ROOT>`, the checks to run, and the output path for the\",\n \" audit report.\",\n \"\",\n \"2. **Walk the doc tree.** Enumerate every file under `<DOCS_ROOT>`\",\n \" that matches the doc-extension convention (typically `*.md`).\",\n \"\",\n \"3. **Run each declared check.** For each finding, capture:\",\n \" - The check category (from the catalog above)\",\n \" - The source file path and line (if applicable)\",\n \" - The target that triggered the finding (broken link target,\",\n \" orphaned doc path, drifted registry entry, etc.)\",\n \" - A suggested fix category (`prune`, `normalize`, `regenerate`,\",\n \" `flag-for-human`)\",\n \"\",\n \"4. **Write the audit report** to:\",\n \" ```\",\n \" <AUDIT_ROOT>/maint-audit-<AUDIT_SLUG>-<YYYY-MM-DD>.md\",\n \" ```\",\n \"\",\n \" Format:\",\n \" ```markdown\",\n \" ---\",\n ' title: \"Maintenance Audit: <AUDIT_SLUG>\"',\n \" date: YYYY-MM-DD\",\n \" parent_issue: <N>\",\n \" status: complete\",\n \" ---\",\n \"\",\n \" # Maintenance Audit: <AUDIT_SLUG>\",\n \"\",\n \" ## Scope\",\n \" - **Docs root:** `<DOCS_ROOT>`\",\n \" - **Checks run:** <list of check categories>\",\n \" - **Files scanned:** <count>\",\n \"\",\n \" ## Findings Summary\",\n \" | Category | Count | Auto-fixable | Needs human |\",\n \" |----------|-------|--------------|-------------|\",\n \" | Broken xref | N | N | N |\",\n \" | Orphaned doc | N | N | N |\",\n \" | Registry drift | N | N | N |\",\n \" | Stale index | N | N | N |\",\n \" | Duplicate ID | N | N | N |\",\n \" | Missing traceability | N | N | N |\",\n \" | Dangling backlink | N | N | N |\",\n \"\",\n \" ## Findings\",\n \"\",\n \" ### Finding 1: <category> — <short description>\",\n \" - **File:** <path>:<line>\",\n \" - **Target:** <broken target or drifted entry>\",\n \" - **Suggested fix:** prune / normalize / regenerate / flag-for-human\",\n \" - **Notes:** <any context that helps the fix phase>\",\n \"\",\n \" ## Findings Requiring Human Judgment\",\n \" <list of findings where the fix phase must NOT auto-apply>\",\n \"\",\n \" ## Out-of-Scope Observations\",\n \" <incidental issues noticed during the walk but outside the\",\n \" declared scope — e.g. a sibling doc tree that also looks stale.\",\n \" Recorded here so a human can decide whether to queue a follow-up\",\n \" cycle. Not acted on in this cycle.>\",\n \" ```\",\n \"\",\n \"5. **Decide the next step:**\",\n \" - **No findings** → comment on the scan issue noting a clean\",\n \" audit, commit the (still valuable) empty report, close the\",\n \" issue. Do not create a `maint:fix` issue.\",\n \" - **All findings need human judgment** → commit the report,\",\n \" comment on the scan issue summarizing the findings, apply\",\n \" `status:needs-attention`, and close the issue. Do not create\",\n \" a `maint:fix` issue.\",\n \" - **At least one auto-fixable finding** → create a `maint:fix`\",\n \" issue (blocked on this scan issue via `Depends on: #N`). The\",\n \" fix issue body must reference the audit report path and\",\n \" enumerate the auto-fix categories to apply.\",\n \"\",\n \"6. **Commit and push.**\",\n \"\",\n \"---\",\n \"\",\n \"## Phase 2: Fix (`maint:fix`)\",\n \"\",\n \"**Goal:** Read the audit report, apply idempotent fixes, verify\",\n \"they cleared the reported findings, and commit the doc-tree changes.\",\n \"\",\n \"**Budget:** Bounded edits to files under `<DOCS_ROOT>` plus a final\",\n \"verification re-run of the checks from Phase 1. No new audit\",\n \"categories. No fixes that require authoring new content.\",\n \"\",\n \"### Fix Categories\",\n \"\",\n \"Apply only the categories the fix issue body enumerates. Defaults:\",\n \"\",\n \"| Category | What it does | Safety |\",\n \"|----------|-------------|--------|\",\n \"| **prune** | Remove stale entries from registries/indexes that point to non-existent docs. | Safe — only deletes references the scan confirmed are dead. |\",\n \"| **normalize** | Rewrite relative link paths to a canonical form (e.g. always use paths relative to `<DOCS_ROOT>`, always include file extensions). | Safe — preserves target, changes only the link expression. |\",\n \"| **regenerate** | Rebuild an index or registry file from the authoritative source (the filesystem or a declared source-of-truth file). | Safe IF the source-of-truth is unambiguous. Otherwise flag-for-human. |\",\n \"| **flag-for-human** | Do not auto-apply. Leave the finding in place and note it in the fix report. | Used for ambiguous category assignments, duplicate IDs, or missing targets where the correct target is unclear. |\",\n \"\",\n \"### Steps\",\n \"\",\n \"1. **Read the audit report** referenced in the fix issue body.\",\n \"\",\n \"2. **Partition findings.** Group findings by fix category. Confirm\",\n \" each auto-fixable finding still matches what the report\",\n \" recorded (docs may have moved since the scan) — if a finding no\",\n \" longer applies, note it as `stale-finding` and skip.\",\n \"\",\n \"3. **Apply fixes in deterministic order:**\",\n \" 1. **prune** — remove dead registry entries first. This reduces\",\n \" the surface area for downstream fixes.\",\n \" 2. **normalize** — rewrite link expressions to canonical form.\",\n \" 3. **regenerate** — rebuild indexes last, from the now-clean\",\n \" tree.\",\n \"\",\n \"4. **Never author new content.** If a finding requires inventing a\",\n \" target (e.g. a broken link where no candidate target exists),\",\n \" mark it `flag-for-human` and skip. Authoring new docs belongs\",\n \" to the writer agent for that doc type, not this agent.\",\n \"\",\n \"5. **Verify.** Re-run the same checks the scan phase ran, scoped\",\n \" to the files the fix phase touched (plus any index files those\",\n \" edits affect). Every finding the fix phase claimed to resolve\",\n \" must now be gone. Any finding that remains is a regression —\",\n \" revert the corresponding edit and mark it `flag-for-human`.\",\n \"\",\n \"6. **Write the fix report** to:\",\n \" ```\",\n \" <AUDIT_ROOT>/maint-fix-<AUDIT_SLUG>-<YYYY-MM-DD>.md\",\n \" ```\",\n \"\",\n \" Format:\",\n \" ```markdown\",\n \" ---\",\n ' title: \"Maintenance Fix: <AUDIT_SLUG>\"',\n \" date: YYYY-MM-DD\",\n \" parent_issue: <N>\",\n \" audit_report: <path to scan report>\",\n \" status: complete\",\n \" ---\",\n \"\",\n \" # Maintenance Fix: <AUDIT_SLUG>\",\n \"\",\n \" ## Source Audit Report\",\n \" <link to the Phase 1 audit report>\",\n \"\",\n \" ## Fixes Applied\",\n \" | Category | Count | Files touched |\",\n \" |----------|-------|---------------|\",\n \" | prune | N | <list> |\",\n \" | normalize | N | <list> |\",\n \" | regenerate | N | <list> |\",\n \"\",\n \" ## Skipped\",\n \" <findings that were stale, flagged for human, or reverted\",\n \" during verification — one entry each, with the reason>\",\n \"\",\n \" ## Verification\",\n \" - **Re-scan result:** clean / <N> residual findings\",\n \" - **Residual findings:** <list, with reasons — each becomes a\",\n \" follow-up `flag-for-human` note>\",\n \" ```\",\n \"\",\n \"7. **Comment on the scan issue** with a summary of what was fixed,\",\n \" what was skipped, and any residual findings.\",\n \"\",\n \"8. **Commit and push.**\",\n \"\",\n \"---\",\n \"\",\n \"## Coordination with Other Agents\",\n \"\",\n \"| Direction | Agent | What |\",\n \"|-----------|-------|------|\",\n \"| Downstream (last resort) | Writer agent for the audited doc type | When the audit surfaces findings that require authoring new content (missing target, partial coverage that can only be resolved by writing a new doc), the fix phase flags them for human — the human may then dispatch the appropriate writer agent. This agent never opens writer-agent issues itself. |\",\n \"\",\n \"**File boundaries:** Writes audit and fix reports to\",\n \"`<AUDIT_ROOT>/`. Applies bounded, idempotent edits under\",\n \"`<DOCS_ROOT>/` per the fix-policy declared in the fix issue body.\",\n \"Never writes to source code, never writes to doc trees outside\",\n \"`<DOCS_ROOT>`, never authors new document files to close a gap.\",\n \"\",\n \"---\",\n \"\",\n \"## Blocked Issues\",\n \"\",\n \"Additional block reasons specific to maintenance audits:\",\n \"- `<DOCS_ROOT>` is undefined or does not exist in the repo\",\n \"- The registry file format is ambiguous (no declared schema)\",\n \"- All findings are `flag-for-human` and the fix issue has nothing\",\n \" to auto-apply — resolve by closing the fix issue with a summary\",\n \" instead\",\n \"\",\n \"---\",\n \"\",\n \"## Rules\",\n \"\",\n \"- **Audit before fix.** Never apply a fix whose finding is not\",\n \" recorded in the audit report referenced by the fix issue.\",\n \"- **Idempotent fixes only.** If re-running the same fix twice\",\n \" would produce a different result, it is not an idempotent fix.\",\n \" Mark it `flag-for-human` instead.\",\n \"- **Bounded scope.** Do not expand the audit scope mid-session.\",\n \" Record out-of-scope observations in the report for human review.\",\n \"- **No authoring.** Do not invent new document content to close a\",\n \" finding. That work belongs to the writer agent for the doc type.\",\n \"- **Verify before closing.** Always re-run the checks after\",\n \" applying fixes and record the result in the fix report.\",\n ].join(\"\\n\"),\n};\n\n/** Skill that kicks off a maintenance audit cycle. */\nconst maintenanceAuditSkill: AgentSkill = {\n name: \"audit-docs\",\n description:\n \"Kick off a documentation-maintenance audit cycle (scan → fix). Creates a maint:scan issue for the supplied scope and dispatches Phase 1.\",\n disableModelInvocation: true,\n userInvocable: true,\n context: \"fork\",\n agent: \"maintenance-audit\",\n platforms: { cursor: { exclude: true } },\n instructions: [\n \"# Audit Docs\",\n \"\",\n \"Kick off a maintenance-audit cycle against a configurable doc\",\n \"tree. Creates a `maint:scan` issue targeted at the requested\",\n \"scope and dispatches Phase 1 (Scan) in the maintenance-audit\",\n \"agent.\",\n \"\",\n \"## Usage\",\n \"\",\n \"/audit-docs <scope>\",\n \"\",\n \"Where `<scope>` is a short slug plus path for the doc tree to\",\n \"audit. Examples:\",\n \"- `requirements-xrefs:docs/requirements/` — audit requirement\",\n \" traceability links and the category registries\",\n \"- `adr-registry:docs/adrs/` — audit the ADR registry index\",\n \"- `bcm-traceability:docs/bcm/` — audit BCM capability-model\",\n \" cross-references\",\n \"\",\n \"The consuming project defines which scopes are valid.\",\n \"\",\n \"## Steps\",\n \"\",\n \"1. Create a `maint:scan` issue with `type:maintenance`,\",\n \" `priority:medium`, and `status:ready`. Body must list:\",\n \" - `<DOCS_ROOT>` — the doc tree to audit\",\n \" - `<AUDIT_ROOT>` — where to write the audit report\",\n \" - `<AUDIT_SLUG>` — short identifier for this audit\",\n \" - The audit checks to run (defaults to the full check catalog)\",\n \"2. Execute Phase 1 (Scan) of the maintenance-audit agent.\",\n \"3. If auto-fixable findings exist, a `maint:fix` issue is created\",\n \" automatically.\",\n \"\",\n \"## Output\",\n \"\",\n \"- A `maint-audit-<slug>-<YYYY-MM-DD>.md` report under\",\n \" `<AUDIT_ROOT>`.\",\n \"- A `maint:fix` issue if auto-fixable findings were found.\",\n ].join(\"\\n\"),\n};\n\n/**\n * Maintenance-audit bundle — enabled by default.\n *\n * Consuming projects can disable it with\n * `excludeBundles: [\"maintenance-audit\"]`. `appliesWhen` always returns\n * `true` per this batch's directive that bundles assume peers are\n * present.\n *\n * Provides a 2-phase documentation-maintenance pipeline (scan → fix)\n * designed for any project with structured doc registries and\n * cross-references. Ships a sub-agent, a user-invocable skill, and\n * `maint:*` phase labels via the bundle `labels` mechanism so\n * consuming projects automatically pick up the label taxonomy\n * through the sync-labels workflow.\n */\nexport const maintenanceAuditBundle: AgentRuleBundle = {\n name: \"maintenance-audit\",\n description:\n \"Documentation-maintenance agent bundle. 2-phase pipeline (scan, fix) with maint:* phase labels for auditing registries and cross-references and applying idempotent fixes. Enabled by default.\",\n appliesWhen: () => true,\n rules: [\n {\n name: \"maintenance-audit-workflow\",\n description:\n \"Describes the 2-phase documentation-maintenance pipeline, the maint:* label taxonomy, and the audit-before-fix boundary.\",\n scope: AGENT_RULE_SCOPE.ALWAYS,\n content: [\n \"# Maintenance Audit Workflow\",\n \"\",\n \"Use `/audit-docs <scope>` to kick off a documentation-maintenance\",\n \"audit cycle. The pipeline runs in 2 phases — scan and fix — each\",\n \"tracked by its own GitHub issue labeled `maint:scan` or\",\n \"`maint:fix`. All issues carry `type:maintenance`.\",\n \"\",\n \"The maintenance-audit agent *audits doc registries and applies\",\n \"idempotent fixes*; it does **not** author new document content.\",\n \"Findings that would require authoring new docs are flagged for\",\n \"human review so the appropriate writer agent can be dispatched.\",\n \"\",\n \"See the `maintenance-audit` agent definition for full workflow\",\n \"details and phase-by-phase instructions.\",\n ].join(\"\\n\"),\n platforms: {\n cursor: { exclude: true },\n },\n tags: [\"workflow\"],\n },\n ],\n skills: [maintenanceAuditSkill],\n subAgents: [maintenanceAuditSubAgent],\n labels: [\n {\n name: \"type:maintenance\",\n color: \"5319E7\",\n description:\n \"Work that audits or fixes documentation registries, cross-references, or indexes\",\n },\n {\n name: \"maint:scan\",\n color: \"C5DEF5\",\n description:\n \"Phase 1: scan doc tree for broken xrefs, registry drift, and stale indexes\",\n },\n {\n name: \"maint:fix\",\n color: \"BFDADC\",\n description:\n \"Phase 2: apply idempotent fixes from a maintenance audit report\",\n },\n ],\n};\n","import { AgentRuleBundle } from \"../agent-config-options\";\nimport { PROJECT_CONTEXT_MAINTAINER_SECTION } from \"./project-context\";\nimport {\n AGENT_MODEL,\n AGENT_RULE_SCOPE,\n AgentSkill,\n AgentSubAgent,\n} from \"../types\";\n\n/** Sub-agent that processes meeting transcripts through the 4-phase pipeline. */\nconst meetingAnalystSubAgent: AgentSubAgent = {\n name: \"meeting-analyst\",\n description:\n \"Processes meeting transcripts through a 4-phase pipeline: extract, notes, draft, and link\",\n model: AGENT_MODEL.POWERFUL,\n maxTurns: 80,\n platforms: { cursor: { exclude: true } },\n prompt: [\n \"# Meeting Analyst Agent\",\n \"\",\n \"You process meeting transcripts through a structured 4-phase pipeline.\",\n \"Each phase runs as a **separate agent session**, triggered by its own\",\n \"GitHub issue with a `meeting:*` phase label. You handle exactly **one\",\n \"phase per session** — read the issue to determine which phase to execute.\",\n \"\",\n \"## Execution Model\",\n \"\",\n \"1. Each meeting produces up to 4 GitHub issues (one per phase)\",\n \"2. Each issue carries a `meeting:*` label identifying the phase\",\n \"3. You pick up one issue, execute that phase, commit/push, then close the issue\",\n \"4. Phase 1 (Extract) creates the downstream phase issues for phases 2-4\",\n \"5. Each downstream issue includes `Depends on: #N` linking to its predecessor\",\n \"\",\n \"## Design Principles\",\n \"\",\n \"1. **Extract, don't interpret.** Capture what was said and decided. Flag\",\n \" ambiguity as open items rather than resolving it.\",\n \"2. **Route to the right category.** Meeting content maps to requirements,\",\n \" ADRs, product docs, and business strategy. Each output goes to the\",\n \" correct location per the project's taxonomy.\",\n \"3. **Preserve provenance.** Every extracted item links back to the meeting\",\n \" source so reviewers can check context.\",\n \"4. **Create issues, not documents.** For requirements and ADRs, create\",\n \" GitHub issues that other agents or humans will pick up. Do not write\",\n \" final requirement documents yourself.\",\n \"5. **Bi-directional traceability.** Every document and issue created by\",\n \" this pipeline must link back to the meeting source, and the meeting\",\n \" source documents must link forward to everything created from them.\",\n \"\",\n \"---\",\n \"\",\n ...PROJECT_CONTEXT_MAINTAINER_SECTION,\n \"## Traceability\",\n \"\",\n \"All outputs must be bi-directionally linked so any artifact can be traced\",\n \"back to the meeting that produced it and forward to everything it spawned.\",\n \"\",\n \"### Backward links (created artifact → meeting source)\",\n \"\",\n \"Every GitHub issue and document created by this pipeline must include a\",\n \"`## Traceability` section with:\",\n \"\",\n \"```markdown\",\n \"## Traceability\",\n \"\",\n \"- **Source meeting:** <path to transcript or meeting notes>\",\n \"- **Extraction:** <path to extraction file>\",\n \"- **Phase issue:** #<N> (the phase issue that created this artifact)\",\n \"```\",\n \"\",\n \"### Forward links (meeting source → created artifacts)\",\n \"\",\n \"After Phase 4 (Link) creates all follow-up issues and documents:\",\n \"\",\n \"1. **Update the extraction file** with a `## Downstream Artifacts` section\",\n \" listing every issue and document created from this meeting:\",\n \"\",\n \" ```markdown\",\n \" ## Downstream Artifacts\",\n \"\",\n \" | Artifact | Type | Issue/Path |\",\n \" |----------|------|------------|\",\n \" | <title> | requirement / ADR / action-item / profile | #<N> or <path> |\",\n \" ```\",\n \"\",\n \"2. **Update the meeting notes** with a similar `## Related Issues` section\",\n \" listing all issues created from this meeting.\",\n \"\",\n \"3. **Comment on the extract issue** with a summary linking to all created\",\n \" artifacts.\",\n \"\",\n \"### Within-pipeline links\",\n \"\",\n \"- Phase issues link to predecessors via `Depends on: #N`\",\n \"- Phase issues reference the extraction file path in their body\",\n \"- Draft documents reference both the extraction and the meeting notes\",\n \"\",\n \"---\",\n \"\",\n \"## Phase 1: Extract (`meeting:extract`)\",\n \"\",\n \"**Goal:** Read the meeting transcript and categorize all substantive content.\",\n \"\",\n \"### Steps\",\n \"\",\n \"1. Read the transcript file specified in the issue body.\",\n \"2. Identify and categorize content into these buckets:\",\n \"\",\n \" | Bucket | What to look for |\",\n \" |--------|-----------------|\",\n ' | **Decisions** | \"We decided...\", \"Let\\'s go with...\", explicit choices |',\n ' | **Requirements** | Feature descriptions, acceptance criteria, \"it should...\" |',\n \" | **Technology discussions** | Platform comparisons, architecture options, tool evaluations |\",\n ' | **Action items** | \"[Person] will...\", \"Next step is...\", assigned tasks |',\n ' | **Open questions** | \"We need to figure out...\", unresolved debates |',\n \" | **People of interest** | Industry contacts, domain experts mentioned |\",\n \" | **Companies of interest** | Competitors, vendors, partners discussed |\",\n \" | **Strategic direction** | Business model changes, market positioning |\",\n \" | **Product direction** | Roadmap changes, feature prioritization |\",\n \"\",\n \"3. Write the extraction to a markdown file with structured sections:\",\n \" - Attendees\",\n \" - Decisions Made (with category and confidence: Firm / Tentative / Needs confirmation)\",\n \" - Requirements Identified (with category and priority estimate)\",\n \" - Technology Discussions (with status: Decided / Leaning toward / Open)\",\n \" - Action Items (with assignee and due date if stated)\",\n \" - Open Questions\",\n \" - People of Interest (with context and whether a profile exists)\",\n \" - Companies of Interest (with type and context)\",\n \" - Strategic / Product Direction\",\n \"\",\n \"4. **Create downstream phase issues** using `gh issue create`:\",\n \" - Always create a `meeting:notes` issue (blocked on this extract issue)\",\n \" - If requirements OR decisions/ADRs identified, create a `meeting:draft` issue\",\n \" (blocked on the notes issue)\",\n \" - Always create a `meeting:link` issue — blocked on the draft issue if one\",\n \" was created, otherwise blocked on the notes issue\",\n \"\",\n \"5. Commit, push, and close the extract issue.\",\n \"\",\n \"---\",\n \"\",\n \"## Phase 2: Notes (`meeting:notes`)\",\n \"\",\n \"**Goal:** Transform the extraction into structured meeting notes.\",\n \"\",\n \"### Steps\",\n \"\",\n \"1. Read the extraction file referenced in the issue body (output of Phase 1).\",\n \"2. Write structured meeting notes with these sections:\",\n \" - Meeting metadata (title, date, attendees)\",\n \" - Agenda / topics covered\",\n \" - Key Discussion Points (organized by topic)\",\n \" - Decisions (numbered, with rationale)\",\n \" - Action Items (table: who, what, when)\",\n \" - Open Questions\",\n \" - Follow-up items\",\n \"3. Commit, push, and close the notes issue.\",\n \"\",\n \"---\",\n \"\",\n \"## Phase 3: Draft (`meeting:draft`)\",\n \"\",\n \"**Goal:** Draft proposals for requirements, ADRs, and product/strategy updates.\",\n \"\",\n \"This phase only exists if the extraction identified requirements, architectural\",\n \"decisions, or strategy changes. If this issue exists, execute it.\",\n \"\",\n \"### Steps\",\n \"\",\n \"1. Read the extraction file from Phase 1.\",\n \"2. Check existing requirement registries and ADR registries for duplicates.\",\n \"3. Draft requirement proposals with:\",\n \" - Category (FR, BR, NFR, etc.)\",\n \" - Summary (2-3 sentences)\",\n \" - Draft acceptance criteria\",\n \" - Related existing requirements\",\n \"4. Draft ADR proposals for technology decisions with:\",\n \" - Context and problem statement\",\n \" - Options discussed\",\n \" - Stated preferences or decisions\",\n \" - Status: Proposed or Decided\",\n \"5. Summarize product/strategy document updates needed.\",\n \"6. Commit, push, and close the draft issue.\",\n \"\",\n \"---\",\n \"\",\n \"## Phase 4: Link (`meeting:link`)\",\n \"\",\n \"**Goal:** Create GitHub issues for follow-up work, cross-reference the\",\n \"meeting into existing documentation, and complete bi-directional traceability.\",\n \"\",\n \"### Steps\",\n \"\",\n \"1. Read the drafts from Phase 3 (if they exist) and the extraction from Phase 1.\",\n \"2. Create requirement issues using `gh issue create` with appropriate labels.\",\n \" Include a `## Traceability` section in each issue body linking back to\",\n \" the source meeting and extraction file.\",\n \"3. Create ADR issues if technology decisions need formal records.\",\n \" Include a `## Traceability` section in each.\",\n \"4. Create action item issues for tasks that are not document-related.\",\n \" Include a `## Traceability` section in each.\",\n \"5. Cross-reference the meeting in any existing documents that were discussed.\",\n \"6. Apply direct product/strategy doc updates for items flagged as **Firm**\",\n \" confidence in the extraction.\",\n \"7. **Update the extraction file** with a `## Downstream Artifacts` section\",\n \" listing every issue and document created from this meeting.\",\n \"8. **Update the meeting notes** with a `## Related Issues` section listing\",\n \" all issues created from this meeting.\",\n \"9. Comment on the parent extract issue with a summary linking to all\",\n \" created artifacts.\",\n \"10. Commit and push (if any file changes were made), then close the link issue.\",\n \"\",\n \"---\",\n \"\",\n \"## GitHub Integration\",\n \"\",\n \"- Use `gh` CLI for all GitHub operations\",\n \"- Apply the appropriate `meeting:*` phase label to each phase issue\",\n \"- Use `type:docs` for documentation-producing issues, `type:chore` for\",\n \" maintenance/organizational tasks\",\n \"- Use `status:` labels to track progress (`status:ready`, `status:in-progress`, `status:done`)\",\n \"- Reference the source meeting transcript in all created issues\",\n \"- Link phase issues with `Depends on: #N` to enforce ordering\",\n \"\",\n \"## When to Shorten the Pipeline\",\n \"\",\n \"- **Short meetings** (<30 min, <2000 words): combine extract + notes into one session\",\n \"- **No requirements or decisions**: Phase 1 skips creating the `meeting:draft` issue\",\n \"- **Only action items**: extract + notes + link (3 phase issues)\",\n ].join(\"\\n\"),\n};\n\n/** Skill that kicks off meeting transcript processing. */\nconst processMeetingSkill: AgentSkill = {\n name: \"process-meeting\",\n description:\n \"Process a meeting transcript through the 4-phase meeting analysis pipeline\",\n disableModelInvocation: true,\n userInvocable: true,\n context: \"fork\",\n agent: \"meeting-analyst\",\n platforms: { cursor: { exclude: true } },\n instructions: [\n \"# Process Meeting Transcript\",\n \"\",\n \"Kick off meeting transcript processing by executing Phase 1 (Extract)\",\n \"and creating downstream phase issues for the remaining phases.\",\n \"\",\n \"## Usage\",\n \"\",\n \"/process-meeting <path-to-transcript>\",\n \"\",\n \"## Steps\",\n \"\",\n \"1. Read the provided transcript file\",\n \"2. Execute Phase 1 (Extract) — categorize transcript content into\",\n \" decisions, requirements, action items, open questions, and more\",\n \"3. Write the extraction to a markdown file\",\n \"4. Create downstream phase issues using `gh issue create`:\",\n \" - `meeting:notes` issue (always)\",\n \" - `meeting:draft` issue (if requirements or decisions were found)\",\n \" - `meeting:link` issue (always)\",\n \"5. Each downstream issue includes `Depends on:` linking to its predecessor\",\n \"6. Commit and push the extraction file\",\n \"\",\n \"## Input\",\n \"\",\n \"Provide a path to a meeting transcript file (text or markdown).\",\n \"The transcript should contain speaker-attributed dialogue.\",\n \"\",\n \"## Output\",\n \"\",\n \"- An extraction markdown file with categorized meeting content\",\n \"- Phase issues with `meeting:*` labels for downstream agent sessions\",\n \" to pick up (notes, draft, link)\",\n ].join(\"\\n\"),\n};\n\n/**\n * Meeting analysis bundle — included by default.\n * Provides a 4-phase meeting transcript processing workflow.\n */\nexport const meetingAnalysisBundle: AgentRuleBundle = {\n name: \"meeting-analysis\",\n description:\n \"Meeting transcript processing workflow with 4-phase pipeline (extract, notes, draft, link)\",\n appliesWhen: () => true,\n rules: [\n {\n name: \"meeting-processing-workflow\",\n description:\n \"Describes the 4-phase meeting processing pipeline, extraction taxonomy, and labeling conventions\",\n scope: AGENT_RULE_SCOPE.ALWAYS,\n content: [\n \"# Meeting Processing Workflow\",\n \"\",\n \"Use `/process-meeting <path>` to process a meeting transcript through a\",\n \"4-phase pipeline (extract → notes → draft → link). Each phase runs as a\",\n \"separate agent session tracked by a GitHub issue with a `meeting:*` label.\",\n \"See the `meeting-analyst` agent definition for full workflow details.\",\n ].join(\"\\n\"),\n platforms: {\n cursor: { exclude: true },\n },\n tags: [\"workflow\"],\n },\n ],\n skills: [processMeetingSkill],\n subAgents: [meetingAnalystSubAgent],\n labels: [\n {\n name: \"meeting:extract\",\n color: \"C5DEF5\",\n description: \"Phase 1: raw extraction from a meeting transcript\",\n },\n {\n name: \"meeting:notes\",\n color: \"BFDADC\",\n description: \"Phase 2: curated notes derived from an extraction\",\n },\n {\n name: \"meeting:draft\",\n color: \"D4C5F9\",\n description: \"Phase 3: draft follow-up issues proposed from notes\",\n },\n {\n name: \"meeting:link\",\n color: \"FEF2C0\",\n description:\n \"Phase 4: linking/reconciling drafted issues with existing work\",\n },\n ],\n};\n","import { AgentRuleBundle } from \"../agent-config-options\";\nimport { PROJECT_CONTEXT_READER_SECTION } from \"./project-context\";\nimport {\n AGENT_MODEL,\n AGENT_RULE_SCOPE,\n AgentProcedure,\n AgentSubAgent,\n} from \"../types\";\n\n/*******************************************************************************\n *\n * check-blocked.sh — Token-efficient issue triage for agent loops.\n *\n ******************************************************************************/\n\nconst checkBlockedProcedure: AgentProcedure = {\n name: \"check-blocked.sh\",\n description:\n \"Token-efficient issue triage script with subcommands: eligible, unblock, stale, orphaned, prs\",\n content: [\n \"#!/usr/bin/env bash\",\n \"# check-blocked.sh — Token-efficient issue triage for agent loops.\",\n \"# Replaces inline body-parsing with shell pipelines that return only\",\n \"# actionable summaries.\",\n \"#\",\n \"# Usage:\",\n \"# .claude/procedures/check-blocked.sh unblock\",\n \"# .claude/procedures/check-blocked.sh eligible\",\n \"# .claude/procedures/check-blocked.sh stale\",\n \"# .claude/procedures/check-blocked.sh orphaned\",\n \"# .claude/procedures/check-blocked.sh prs\",\n \"\",\n \"set -uo pipefail\",\n \"\",\n \"# ── constants ────────────────────────────────────────────────────────\",\n \"\",\n \"STALE_IN_PROGRESS_HOURS=72\",\n \"STALE_BLOCKED_HOURS=168\",\n \"\",\n \"# ── helpers ──────────────────────────────────────────────────────────\",\n \"\",\n '# Extract issue numbers from a \"Depends on:\" line.',\n '# Returns space-separated numbers, or empty string for \"(none)\".',\n \"parse_deps() {\",\n ' local line=\"$1\"',\n \" if echo \\\"$line\\\" | grep -qi '(none)'; then\",\n ' echo \"\"',\n \" return\",\n \" fi\",\n \" echo \\\"$line\\\" | grep -oE '#[0-9]+' | tr -d '#' | tr '\\\\n' ' ' || echo \\\"\\\"\",\n \"}\",\n \"\",\n \"# Check if a single issue is closed. Returns 0 if closed, 1 if open.\",\n \"is_closed() {\",\n \" local state\",\n ' state=$(gh issue view \"$1\" --json state --jq \\'.state\\' 2>/dev/null || echo \"UNKNOWN\")',\n ' [[ \"$state\" == \"CLOSED\" ]]',\n \"}\",\n \"\",\n \"# ── subcommands ──────────────────────────────────────────────────────\",\n \"\",\n \"cmd_unblock() {\",\n \" local issues\",\n ' issues=$(gh issue list --label \"status:blocked\" --state open \\\\',\n ' --json number,body --limit 50 2>/dev/null || echo \"[]\")',\n \"\",\n \" local count\",\n \" count=$(echo \\\"$issues\\\" | jq 'length')\",\n ' if [[ \"$count\" -eq 0 ]]; then',\n ' echo \"NO_BLOCKED_ISSUES\"',\n \" return 0\",\n \" fi\",\n \"\",\n \" local issue_data\",\n ' issue_data=$(echo \"$issues\" | jq -r \\'',\n \" .[] |\",\n ' (.body | split(\"\\\\n\") | map(select(test(\"Depends on:\"; \"i\"))) | .[0] // \"\") as $dep_line |',\n ' \"\\\\(.number)\\\\t\\\\($dep_line)\"',\n \" ')\",\n \"\",\n \" while IFS=$'\\\\t' read -r num dep_line; do\",\n ' [[ -z \"$num\" ]] && continue',\n \"\",\n ' if [[ -z \"$dep_line\" ]]; then',\n ' echo \"BLOCKED #${num} — no Depends on field found\"',\n \" continue\",\n \" fi\",\n \"\",\n \" local deps\",\n ' deps=$(parse_deps \"$dep_line\")',\n ' if [[ -z \"${deps// /}\" ]]; then',\n ' echo \"UNBLOCK #${num} — no dependencies\"',\n \" continue\",\n \" fi\",\n \"\",\n \" local all_closed=true\",\n ' local open_deps=\"\"',\n ' local closed_deps=\"\"',\n \" for dep in $deps; do\",\n ' if is_closed \"$dep\"; then',\n ' closed_deps=\"${closed_deps}#${dep} \"',\n \" else\",\n \" all_closed=false\",\n ' open_deps=\"${open_deps}#${dep} \"',\n \" fi\",\n \" done\",\n \"\",\n \" if $all_closed; then\",\n ' echo \"UNBLOCK #${num} — all deps closed (${closed_deps% })\"',\n \" else\",\n ' echo \"BLOCKED #${num} — waiting on ${open_deps% }\"',\n \" fi\",\n ' done <<< \"$issue_data\"',\n \"}\",\n \"\",\n \"cmd_eligible() {\",\n \" local issues\",\n ' issues=$(gh issue list --label \"status:ready\" --state open \\\\',\n ' --search \"sort:created-asc\" \\\\',\n ' --json number,title,body,labels --limit 50 2>/dev/null || echo \"[]\")',\n \"\",\n \" local count\",\n \" count=$(echo \\\"$issues\\\" | jq 'length')\",\n ' if [[ \"$count\" -eq 0 ]]; then',\n ' echo \"NO_READY_ISSUES\"',\n \" return 0\",\n \" fi\",\n \"\",\n \" local issue_data\",\n ' issue_data=$(echo \"$issues\" | jq -r \\'',\n \" .[] |\",\n ' (.body | split(\"\\\\n\") | map(select(test(\"Depends on:\"; \"i\"))) | .[0] // \"\") as $dep_line |',\n ' (.labels | map(.name) | join(\",\")) as $label_str |',\n ' (.labels | map(.name) | map(select(startswith(\"type:\"))) | .[0] // \"\") as $type_label |',\n ' \"\\\\(.number)\\\\t\\\\(.title)\\\\t\\\\($dep_line)\\\\t\\\\($label_str)\\\\t\\\\($type_label)\"',\n \" ')\",\n \"\",\n ' local results=\"\"',\n \" while IFS=$'\\\\t' read -r num title dep_line labels_str type_label; do\",\n ' [[ -z \"$num\" ]] && continue',\n \"\",\n ' local deps=\"\"',\n ' if [[ -n \"$dep_line\" ]]; then',\n ' deps=$(parse_deps \"$dep_line\")',\n \" fi\",\n \"\",\n \" # Check if any dep is still open.\",\n \" local has_open_dep=false\",\n ' local open_deps=\"\"',\n ' if [[ -n \"${deps// /}\" ]]; then',\n \" for dep in $deps; do\",\n ' if ! is_closed \"$dep\"; then',\n \" has_open_dep=true\",\n ' open_deps=\"${open_deps}#${dep} \"',\n \" fi\",\n \" done\",\n \" fi\",\n \"\",\n \" if $has_open_dep; then\",\n ' echo \"SKIP #${num} — dep ${open_deps% } still open\"',\n \" continue\",\n \" fi\",\n \"\",\n \" # 5-level priority sort key.\",\n \" local sort_key=2\",\n ' local priority=\"medium\"',\n ' case \"$labels_str\" in',\n ' *priority:critical*) sort_key=0; priority=\"critical\" ;;',\n ' *priority:high*) sort_key=1; priority=\"high\" ;;',\n ' *priority:medium*) sort_key=2; priority=\"medium\" ;;',\n ' *priority:low*) sort_key=3; priority=\"low\" ;;',\n ' *priority:trivial*) sort_key=4; priority=\"trivial\" ;;',\n \" esac\",\n \"\",\n ' local label_info=\"\"',\n ' [[ -n \"$type_label\" ]] && label_info=\" ${type_label}\"',\n \"\",\n ' results=\"${results}${sort_key}\\\\t${num}\\\\tPICK #${num} priority:${priority}${label_info} \\\\\"${title}\\\\\"\\\\n\"',\n ' done <<< \"$issue_data\"',\n \"\",\n \" # Sort by priority, then issue number (FIFO).\",\n ' if [[ -n \"$results\" ]]; then',\n \" printf '%b' \\\"$results\\\" | sort -t$'\\\\t' -k1,1n -k2,2n | cut -f3\",\n \" fi\",\n \"}\",\n \"\",\n \"cmd_stale() {\",\n \" # Check in-progress issues\",\n \" local ip_issues\",\n ' ip_issues=$(gh issue list --label \"status:in-progress\" --state open \\\\',\n ' --json number,title,updatedAt --limit 50 2>/dev/null || echo \"[]\")',\n \"\",\n \" local ip_count\",\n \" ip_count=$(echo \\\"$ip_issues\\\" | jq 'length')\",\n \"\",\n ' if [[ \"$ip_count\" -gt 0 ]]; then',\n \" local ip_threshold\",\n \" ip_threshold=$(date -u -v-${STALE_IN_PROGRESS_HOURS}H +%Y-%m-%dT%H:%M:%S 2>/dev/null \\\\\",\n ' || date -u -d \"${STALE_IN_PROGRESS_HOURS} hours ago\" +%Y-%m-%dT%H:%M:%S 2>/dev/null)',\n \"\",\n \" local ip_data\",\n ' ip_data=$(echo \"$ip_issues\" | jq -r \\'.[] | \"\\\\(.number)\\\\t\\\\(.title)\\\\t\\\\(.updatedAt)\"\\')',\n \"\",\n \" while IFS=$'\\\\t' read -r num title updated; do\",\n ' [[ -z \"$num\" ]] && continue',\n ' local updated_trimmed=\"${updated%%+*}\"',\n ' updated_trimmed=\"${updated_trimmed%%Z*}\"',\n ' if [[ \"$updated_trimmed\" < \"$ip_threshold\" ]]; then',\n ' local date_part=\"${updated_trimmed%%T*}\"',\n ' echo \"STALE #${num} — no activity since ${date_part} — \\\\\"${title}\\\\\"\"',\n \" fi\",\n ' done <<< \"$ip_data\"',\n \" fi\",\n \"\",\n \" # Check blocked issues\",\n \" local bl_issues\",\n ' bl_issues=$(gh issue list --label \"status:blocked\" --state open \\\\',\n ' --json number,title,updatedAt --limit 50 2>/dev/null || echo \"[]\")',\n \"\",\n \" local bl_count\",\n \" bl_count=$(echo \\\"$bl_issues\\\" | jq 'length')\",\n \"\",\n ' if [[ \"$bl_count\" -gt 0 ]]; then',\n \" local bl_threshold\",\n \" bl_threshold=$(date -u -v-${STALE_BLOCKED_HOURS}H +%Y-%m-%dT%H:%M:%S 2>/dev/null \\\\\",\n ' || date -u -d \"${STALE_BLOCKED_HOURS} hours ago\" +%Y-%m-%dT%H:%M:%S 2>/dev/null)',\n \"\",\n \" local bl_data\",\n ' bl_data=$(echo \"$bl_issues\" | jq -r \\'.[] | \"\\\\(.number)\\\\t\\\\(.title)\\\\t\\\\(.updatedAt)\"\\')',\n \"\",\n \" while IFS=$'\\\\t' read -r num title updated; do\",\n ' [[ -z \"$num\" ]] && continue',\n ' local updated_trimmed=\"${updated%%+*}\"',\n ' updated_trimmed=\"${updated_trimmed%%Z*}\"',\n ' if [[ \"$updated_trimmed\" < \"$bl_threshold\" ]]; then',\n ' local date_part=\"${updated_trimmed%%T*}\"',\n ' echo \"STALE_BLOCKED #${num} — blocked since ${date_part} — \\\\\"${title}\\\\\"\"',\n \" fi\",\n ' done <<< \"$bl_data\"',\n \" fi\",\n \"\",\n ' if [[ \"$ip_count\" -eq 0 && \"$bl_count\" -eq 0 ]]; then',\n ' echo \"NO_STALE_ISSUES\"',\n \" fi\",\n \"}\",\n \"\",\n \"cmd_orphaned() {\",\n \" # Check for remote branches whose issues are closed or missing\",\n \" git fetch --prune origin 2>/dev/null\",\n \" local branches\",\n ' branches=$(git branch -r --format=\"%(refname:short)\" | grep -v HEAD | sed \"s|origin/||\")',\n \"\",\n \" local found_orphan=false\",\n \" while IFS= read -r branch; do\",\n ' [[ -z \"$branch\" ]] && continue',\n ' [[ \"$branch\" == \"main\" || \"$branch\" == \"master\" ]] && continue',\n \"\",\n \" # Extract issue number from branch name (e.g., feat/42-add-login → 42)\",\n \" local issue_num\",\n \" issue_num=$(echo \\\"$branch\\\" | grep -oE '/[0-9]+' | tr -d '/' | head -1)\",\n ' [[ -z \"$issue_num\" ]] && continue',\n \"\",\n \" local state\",\n ' state=$(gh issue view \"$issue_num\" --json state --jq \\'.state\\' 2>/dev/null || echo \"NOT_FOUND\")',\n \"\",\n ' if [[ \"$state\" == \"CLOSED\" ]]; then',\n \" found_orphan=true\",\n ' echo \"ORPHAN_BRANCH ${branch} — issue #${issue_num} is closed\"',\n ' elif [[ \"$state\" == \"NOT_FOUND\" ]]; then',\n \" found_orphan=true\",\n ' echo \"ORPHAN_BRANCH ${branch} — issue #${issue_num} not found\"',\n \" fi\",\n ' done <<< \"$branches\"',\n \"\",\n \" # Check for open PRs whose linked issues are closed\",\n \" local prs\",\n ' prs=$(gh pr list --state open --json number,title,body --limit 50 2>/dev/null || echo \"[]\")',\n \" local pr_data\",\n ' pr_data=$(echo \"$prs\" | jq -r \\'',\n \" .[] |\",\n ' (.body | capture(\"(?:Closes|Fixes|Resolves) #(?<num>[0-9]+)\") | .num) as $issue |',\n ' \"\\\\(.number)\\\\t\\\\(.title)\\\\t\\\\($issue // \"\")\"',\n \" ' 2>/dev/null)\",\n \"\",\n \" while IFS=$'\\\\t' read -r pr_num title issue_num; do\",\n ' [[ -z \"$pr_num\" || -z \"$issue_num\" ]] && continue',\n ' if is_closed \"$issue_num\"; then',\n \" found_orphan=true\",\n ' echo \"ORPHAN_PR #${pr_num} — linked issue #${issue_num} is closed — \\\\\"${title}\\\\\"\"',\n \" fi\",\n ' done <<< \"$pr_data\"',\n \"\",\n \" if ! $found_orphan; then\",\n ' echo \"NO_ORPHANED_RESOURCES\"',\n \" fi\",\n \"}\",\n \"\",\n \"cmd_prs() {\",\n \" local prs\",\n \" prs=$(gh pr list --state open --json number,title,isDraft,headRefName,labels,body \\\\\",\n ' --limit 50 2>/dev/null || echo \"[]\")',\n \"\",\n \" local count\",\n \" count=$(echo \\\"$prs\\\" | jq 'length')\",\n ' if [[ \"$count\" -eq 0 ]]; then',\n ' echo \"NO_OPEN_PRS\"',\n \" return 0\",\n \" fi\",\n \"\",\n \" # Filter: not draft, no needs-attention label.\",\n \" local eligible\",\n ' eligible=$(echo \"$prs\" | jq -r \\'',\n \" .[] |\",\n \" select(.isDraft == false) |\",\n ' select(.labels | map(.name) | index(\"status:needs-attention\") | not) |',\n ' (.body | capture(\"(?:Closes|Fixes|Resolves) #(?<num>[0-9]+)\") | .num) as $issue |',\n ' \"\\\\(.number)\\\\t\\\\(.title)\\\\t\\\\(.headRefName)\\\\t\\\\($issue // \"\")\"',\n \" ' 2>/dev/null)\",\n \"\",\n ' if [[ -z \"$eligible\" ]]; then',\n ' echo \"NO_ELIGIBLE_PRS\"',\n \" return 0\",\n \" fi\",\n \"\",\n \" while IFS=$'\\\\t' read -r pr_num title branch issue_num; do\",\n ' [[ -z \"$pr_num\" ]] && continue',\n \"\",\n ' if [[ -z \"$issue_num\" ]]; then',\n ' echo \"SKIP PR #${pr_num} — no linked issue — \\\\\"${title}\\\\\"\"',\n \" continue\",\n \" fi\",\n \"\",\n \" # Check CI status\",\n \" local failing_checks\",\n ' failing_checks=$(gh pr checks \"$pr_num\" --json name,state \\\\',\n ' --jq \\'[.[] | select(.state != \"SUCCESS\" and .state != \"SKIPPED\")] | length\\' 2>/dev/null || echo \"-1\")',\n \"\",\n ' if [[ \"$failing_checks\" == \"-1\" ]]; then',\n ' echo \"SKIP PR #${pr_num} — could not read CI status — \\\\\"${title}\\\\\"\"',\n \" continue\",\n \" fi\",\n \"\",\n ' if [[ \"$failing_checks\" -gt 0 ]]; then',\n ' echo \"SKIP PR #${pr_num} — ${failing_checks} CI check(s) not passing — \\\\\"${title}\\\\\"\"',\n \" continue\",\n \" fi\",\n \"\",\n \" # Check if already approved\",\n \" local approved\",\n ' approved=$(gh pr view \"$pr_num\" --json reviews \\\\',\n ' --jq \\'[.reviews[] | select(.state == \"APPROVED\")] | length\\' 2>/dev/null || echo \"0\")',\n ' if [[ \"$approved\" -gt 0 ]]; then',\n ' echo \"SKIP PR #${pr_num} — already approved — \\\\\"${title}\\\\\"\"',\n \" continue\",\n \" fi\",\n \"\",\n ' echo \"REVIEW PR #${pr_num} issue:#${issue_num} branch:${branch} — \\\\\"${title}\\\\\"\"',\n ' done <<< \"$eligible\"',\n \"}\",\n \"\",\n \"# ── main ─────────────────────────────────────────────────────────────\",\n \"\",\n 'case \"${1:-help}\" in',\n ' unblock) shift; cmd_unblock \"$@\" ;;',\n ' eligible) shift; cmd_eligible \"$@\" ;;',\n ' stale) shift; cmd_stale \"$@\" ;;',\n ' orphaned) shift; cmd_orphaned \"$@\" ;;',\n ' prs) shift; cmd_prs \"$@\" ;;',\n \" help|*)\",\n ' echo \"Usage: check-blocked.sh <unblock|eligible|stale|orphaned|prs>\"',\n \" exit 1\",\n \" ;;\",\n \"esac\",\n ].join(\"\\n\"),\n};\n\n/*******************************************************************************\n *\n * Orchestrator sub-agent\n *\n ******************************************************************************/\n\nconst orchestratorSubAgent: AgentSubAgent = {\n name: \"orchestrator\",\n description:\n \"Pipeline manager that reviews PRs, triages issues, and identifies the next work item — never implements code\",\n model: AGENT_MODEL.POWERFUL,\n maxTurns: 100,\n platforms: { cursor: { exclude: true } },\n prompt: [\n \"# Orchestrator Agent\",\n \"\",\n \"You are a pipeline manager for the **{{repository.owner}}/{{repository.name}}** repository.\",\n \"You review PRs, triage issues, and identify the next work item. You **never**\",\n \"implement code, create branches for issues, or claim issues.\",\n \"\",\n \"Run the same loop every invocation. Execute all phases in order.\",\n \"\",\n \"---\",\n \"\",\n ...PROJECT_CONTEXT_READER_SECTION,\n \"## Phase A: Startup\",\n \"\",\n \"```bash\",\n \"git checkout main && git pull origin main\",\n \"```\",\n \"\",\n \"## Phase B: Batch PR Review\",\n \"\",\n \"Find all PRs eligible for review:\",\n \"\",\n \"```bash\",\n \".claude/procedures/check-blocked.sh prs\",\n \"```\",\n \"\",\n \"For each `REVIEW PR #N issue:#M branch:<branch>` line:\",\n \"\",\n \"1. Check out the PR branch: `gh pr checkout N`\",\n \"2. Review the PR:\",\n \" - Read the PR description and linked issue: `gh pr view N`\",\n \" - Review the diff: `gh pr diff N`\",\n \" - Check all changed files for correctness, conventions, and test coverage\",\n \" - Verify PR conventions: conventional commit title, closing keyword, summary present\",\n \" - Check CI status: `gh pr checks N`\",\n \"3. If the PR passes review:\",\n \" - Enable squash auto-merge: `gh pr merge N --auto --squash --subject '<conventional-commit-title>' --body '<extended-description>'`\",\n \"4. If the PR fails review:\",\n \" - Request changes: `gh pr review N --request-changes --body '<findings>'`\",\n \"5. After each PR (whether merged or not):\",\n \" ```bash\",\n \" git checkout main && git pull origin main\",\n \" ```\",\n \"\",\n \"Skip lines starting with `SKIP` — those PRs are not eligible.\",\n \"If output is `NO_OPEN_PRS` or `NO_ELIGIBLE_PRS`, skip to Phase C.\",\n \"\",\n \"## Phase C: Triage — Unblock\",\n \"\",\n \"Check for blocked issues whose dependencies have resolved:\",\n \"\",\n \"```bash\",\n \".claude/procedures/check-blocked.sh unblock\",\n \"```\",\n \"\",\n \"For each `UNBLOCK #N` line:\",\n \"```bash\",\n 'gh issue edit N --remove-label \"status:blocked\" --add-label \"status:ready\"',\n 'gh issue comment N --body \"Dependencies resolved — unblocking.\"',\n \"```\",\n \"\",\n \"For `BLOCKED #N — no Depends on field found`: leave as-is (Phase D will\",\n \"catch it if it's been blocked too long).\",\n \"\",\n \"If output is `NO_BLOCKED_ISSUES`, skip to Phase D.\",\n \"\",\n \"## Phase D: Maintenance\",\n \"\",\n \"### D1: Stale Detection\",\n \"\",\n \"```bash\",\n \".claude/procedures/check-blocked.sh stale\",\n \"```\",\n \"\",\n \"For each `STALE #N` line (in-progress >72h without activity):\",\n \"```bash\",\n 'gh issue edit N --add-label \"status:needs-attention\"',\n 'gh issue comment N --body \"Flagged: in-progress for >3 days with no activity.\"',\n \"```\",\n \"\",\n \"For each `STALE_BLOCKED #N` line (blocked >168h):\",\n \"```bash\",\n 'gh issue edit N --add-label \"status:needs-attention\"',\n 'gh issue comment N --body \"Flagged: blocked for >7 days — may need human intervention.\"',\n \"```\",\n \"\",\n \"**Important:** Do NOT auto-reset stale issues to `status:ready` — partial\",\n \"implementation work may exist on a branch.\",\n \"\",\n \"### D2: Orphaned Detection\",\n \"\",\n \"```bash\",\n \".claude/procedures/check-blocked.sh orphaned\",\n \"```\",\n \"\",\n \"Report any `ORPHAN_BRANCH` or `ORPHAN_PR` lines. These indicate branches\",\n \"or PRs whose linked issues are closed or missing. Log them for visibility\",\n \"but do not delete branches automatically.\",\n \"\",\n \"### D3: Needs-Attention Summary\",\n \"\",\n \"List all issues currently flagged:\",\n \"```bash\",\n 'gh issue list --label \"status:needs-attention\" --state open --json number,title',\n \"```\",\n \"\",\n \"Log the count and titles for operator visibility.\",\n \"\",\n \"## Phase E: Queue Scan\",\n \"\",\n \"Find the highest-priority ready issue:\",\n \"\",\n \"```bash\",\n \".claude/procedures/check-blocked.sh eligible\",\n \"```\",\n \"\",\n \"If a `PICK` line is returned, report it as:\",\n \"```\",\n 'NEXT_WORK_ITEM #<number> priority:<level> type:<label> \"<title>\"',\n \"```\",\n \"\",\n \"If output is `NO_READY_ISSUES`, report that the queue is empty.\",\n \"\",\n \"**Do NOT claim the issue, create a branch, or start implementation.**\",\n \"The worker agent handles that.\",\n \"\",\n \"## Phase F: Cleanup\",\n \"\",\n \"```bash\",\n \"git checkout main && git pull origin main\",\n \"git fetch --prune origin\",\n \"```\",\n \"\",\n \"Log completion: phases executed, PRs reviewed, issues unblocked,\",\n \"stale issues flagged, and next work item (if any).\",\n \"\",\n \"---\",\n \"\",\n \"## Rules\",\n \"\",\n \"1. **Never implement code.** You triage, review, and report — you do not code.\",\n \"2. **Never claim issues.** Do not add `status:in-progress` or create branches for issues.\",\n \"3. **Always use check-blocked.sh.** All triage queries go through the shell script for token efficiency.\",\n \"4. **Follow CLAUDE.md conventions** for all git and gh operations.\",\n \"5. **Priority order:** critical > high > medium > low > trivial, then FIFO by issue number.\",\n ].join(\"\\n\"),\n};\n\n/*******************************************************************************\n *\n * Issue Worker sub-agent — selects and works on the next ready issue\n *\n ******************************************************************************/\n\nconst issueWorkerSubAgent: AgentSubAgent = {\n name: \"issue-worker\",\n description:\n \"Selects the next ready issue from the queue, claims it, and implements the change end-to-end following repository conventions\",\n model: AGENT_MODEL.POWERFUL,\n maxTurns: 50,\n canDelegateToAgents: [],\n platforms: { cursor: { exclude: true } },\n prompt: [\n \"# Issue Worker\",\n \"\",\n \"You are the issue worker for **{{repository.owner}}/{{repository.name}}**.\",\n \"Your job is to pick the next issue from the queue, claim it, and implement\",\n \"the change end-to-end — from branch creation through to opening a PR.\",\n \"\",\n \"---\",\n \"\",\n \"## Invocation Mode\",\n \"\",\n \"You operate in one of two modes:\",\n \"\",\n \"- **Interactive mode (default):** A human invoked you directly. You must\",\n \" pause and request explicit user approval before committing code (Phase 6).\",\n \"- **Scheduled mode:** A scheduled task or automation invoked you. You commit,\",\n \" push, and open the PR autonomously without pausing.\",\n \"\",\n \"**You are in scheduled mode if and only if the invocation prompt that\",\n \"started this session contains the literal phrase `scheduled mode` (or\",\n \"`non-interactive`).** Otherwise, default to interactive mode. When in\",\n \"doubt, treat the session as interactive — pausing for approval is always\",\n \"safe; committing without approval is not.\",\n \"\",\n \"---\",\n \"\",\n ...PROJECT_CONTEXT_READER_SECTION,\n \"## Phase 1: Select an Issue\",\n \"\",\n \"If an issue number was provided in your instructions, use that issue.\",\n \"Otherwise, find the next issue to work on:\",\n \"\",\n \"```bash\",\n \".claude/procedures/check-blocked.sh eligible\",\n \"```\",\n \"\",\n \"This returns issues sorted by priority (critical > high > medium > low > trivial),\",\n \"then by issue number (FIFO). Take the **first** `PICK` line.\",\n \"\",\n \"If the output is `NO_READY_ISSUES`, report that the queue is empty and stop.\",\n \"\",\n \"If any `SKIP` lines appear, ignore them — those issues have unresolved dependencies.\",\n \"\",\n \"## Phase 2: Claim the Issue\",\n \"\",\n \"```bash\",\n 'gh issue edit <number> --remove-label \"status:ready\" --add-label \"status:in-progress\"',\n \"```\",\n \"\",\n \"Read the full issue details:\",\n \"```bash\",\n \"gh issue view <number>\",\n \"```\",\n \"\",\n \"## Phase 3: Set Up\",\n \"\",\n \"```bash\",\n \"git checkout {{repository.defaultBranch}} && git pull origin {{repository.defaultBranch}}\",\n \"```\",\n \"\",\n \"Determine the branch type from the issue's `type:*` label or title prefix:\",\n \"\",\n \"| Label / prefix | Branch type |\",\n \"|---------------|-------------|\",\n \"| `type:feat` / `feat:` | `feat/` |\",\n \"| `type:fix` / `fix:` | `fix/` |\",\n \"| `type:chore` / `chore:` | `chore/` |\",\n \"| `type:refactor` / `refactor:` | `refactor/` |\",\n \"| `type:docs` / `docs:` | `docs/` |\",\n \"| `type:release` / `release:` | `release/` |\",\n \"| `type:hotfix` / `hotfix:` | `hotfix/` |\",\n \"| No type label | `feat/` (default) |\",\n \"\",\n \"Create a branch following the naming convention:\",\n \"```bash\",\n \"git checkout -b <type>/<issue-number>-<slug>\",\n \"```\",\n \"\",\n \"The slug should be a short (3-5 word) kebab-case summary derived from the issue title.\",\n \"\",\n \"Link the branch to the issue:\",\n \"```bash\",\n \"gh issue comment <number> --body 'Branch: `<branch-name>`'\",\n \"```\",\n \"\",\n \"## Phase 4: Implement\",\n \"\",\n \"Read the issue body carefully. Understand the acceptance criteria.\",\n \"\",\n \"Implement the change following these guidelines based on issue type:\",\n \"\",\n \"- **feat**: Implement the new feature. Add tests. Export public APIs from `index.ts`.\",\n \"- **fix**: Reproduce the bug first. Write a failing test. Fix the bug. Verify the test passes.\",\n \"- **chore**: Make the maintenance change. Verify no regressions.\",\n \"- **refactor**: Restructure code without changing behavior. Existing tests must pass unchanged.\",\n \"- **docs**: Update documentation only. Do not change source code.\",\n \"\",\n \"Follow all conventions from CLAUDE.md and the project's agent rules.\",\n \"\",\n \"## Phase 5: Verify\",\n \"\",\n \"Run the appropriate verification commands depending on what changed:\",\n \"\",\n \"1. If Projen config was changed: `npx projen && pnpm install`\",\n \"2. Compile the affected package: `pnpm --filter @codedrifters/<package> compile`\",\n \"3. Test the affected package: `pnpm --filter @codedrifters/<package> test`\",\n \"4. If changes span multiple packages: `pnpm build:all`\",\n \"\",\n \"Fix any compilation errors, test failures, or lint errors before proceeding.\",\n \"\",\n \"## Phase 6: Commit and Push\",\n \"\",\n \"**If you are in interactive mode, pause here.** Before running any `git\",\n \"commit`, present the user with a summary of the proposed changes:\",\n \"\",\n \"```bash\",\n \"git status\",\n \"git diff --stat\",\n \"```\",\n \"\",\n \"Then state the conventional commit message you intend to use and ask for\",\n \"explicit approval to commit, push, and open the PR. Do **not** proceed to\",\n \"`git commit` until the user replies with an affirmative response (e.g.,\",\n '\"yes\", \"approved\", \"go ahead\"). If the user requests changes, address',\n \"them and ask again.\",\n \"\",\n \"**If you are in scheduled mode, skip the pause and proceed directly.**\",\n \"\",\n \"Use conventional commit messages:\",\n \"```bash\",\n \"git add <files>\",\n 'git commit -m \"<type>: <description>\"',\n \"git push -u origin <branch-name>\",\n \"```\",\n \"\",\n \"## Phase 7: Open a PR\",\n \"\",\n \"```bash\",\n 'gh pr create --title \"<type>(<scope>): <description>\" --body \"## Summary',\n \"\",\n \"<bullet points>\",\n \"\",\n 'Closes #<issue-number>\"',\n \"```\",\n \"\",\n \"Do **not** enable auto-merge yourself. The `pr-reviewer` sub-agent owns\",\n \"review and merge for every PR — it verifies the diff against the issue's\",\n \"acceptance criteria and enables squash auto-merge only when all checks\",\n \"pass. Record the new PR number so a reviewer can be invoked next.\",\n \"\",\n \"## Phase 8: Update Status\",\n \"\",\n \"After the PR is created, transition the issue to the review phase:\",\n \"```bash\",\n 'gh issue edit <number> --remove-label \"status:in-progress\" --add-label \"status:ready-for-review\"',\n \"```\",\n \"\",\n \"Do **not** set `status:done` here — the `pr-reviewer` sub-agent is\",\n \"responsible for that transition once the PR successfully merges.\",\n \"\",\n \"## Phase 9: Branch Cleanup\",\n \"\",\n \"The PR will not auto-merge until the `pr-reviewer` enables it. Poll the PR\",\n \"state up to 10 times, waiting 30 seconds between polls, until it either\",\n \"merges, closes, or the timeout is reached:\",\n \"\",\n \"```bash\",\n \"gh pr view <pr-number> --json state --jq '.state'\",\n \"```\",\n \"\",\n \"- **If the state becomes `MERGED`:** clean up the local branch.\",\n \" ```bash\",\n \" git checkout {{repository.defaultBranch}}\",\n \" git pull origin {{repository.defaultBranch}}\",\n \" git branch -D <branch-name>\",\n \" ```\",\n \"- **If the state becomes `CLOSED` (not merged):** leave the branch in place\",\n \" and report that the PR was closed without merging. Do not delete the branch.\",\n \"- **If still `OPEN` after the polling window:** report that the PR is\",\n \" awaiting review/merge and stop. Do not delete the branch.\",\n \"\",\n \"---\",\n \"\",\n \"## Rules\",\n \"\",\n \"1. **One issue per session.** Process exactly ONE issue, then stop.\",\n \"2. **Use check-blocked.sh.** Always use the procedure script for issue selection.\",\n \"3. **Follow CLAUDE.md conventions** for branch naming, commits, and PRs.\",\n \"4. **Do not assign PRs to a project board** — this repo has no GitHub project.\",\n \"5. **Do not add AI co-author** attribution to commits.\",\n \"6. **On failure:** If you cannot complete the issue, update labels and leave a comment:\",\n \" ```bash\",\n ' gh issue edit <number> --remove-label \"status:in-progress\" --add-label \"status:needs-attention\"',\n ' gh issue comment <number> --body \"Worker could not complete: <reason>\"',\n \" ```\",\n ].join(\"\\n\"),\n};\n\n/*******************************************************************************\n *\n * Bundle definition\n *\n ******************************************************************************/\n\nexport const orchestratorBundle: AgentRuleBundle = {\n name: \"orchestrator\",\n description:\n \"Pipeline orchestrator agent for issue triage, PR review, and queue management\",\n\n // Always included by default\n appliesWhen: () => true,\n\n rules: [\n {\n name: \"orchestrator-conventions\",\n description:\n \"Guidelines for orchestrator agent behavior and pipeline management\",\n scope: AGENT_RULE_SCOPE.ALWAYS,\n content: [\n \"# Orchestrator Conventions\",\n \"\",\n \"When running the orchestrator agent (`.claude/agents/orchestrator.md`):\",\n \"\",\n \"- The orchestrator **never** implements code or creates branches for issues\",\n \"- It reviews PRs, triages issues, and reports the next work item\",\n \"- All triage queries use `.claude/procedures/check-blocked.sh` for token efficiency\",\n \"- Priority order: critical > high > medium > low > trivial, then FIFO\",\n \"- Stale thresholds: 72h for in-progress, 168h for blocked\",\n \"- Flagged issues get `status:needs-attention` — they are not auto-reset\",\n ].join(\"\\n\"),\n platforms: {\n claude: { target: \"claude-md\" as const },\n cursor: { exclude: true },\n },\n tags: [\"workflow\"],\n },\n ],\n\n subAgents: [orchestratorSubAgent, issueWorkerSubAgent],\n\n procedures: [checkBlockedProcedure],\n\n claudePermissions: {\n allow: [\n // Allow executing the check-blocked.sh procedure\n \"Bash(.claude/procedures/*.sh *)\",\n ],\n },\n};\n","import { AgentRuleBundle } from \"../agent-config-options\";\nimport { PROJECT_CONTEXT_READER_SECTION } from \"./project-context\";\nimport {\n AGENT_MODEL,\n AGENT_RULE_SCOPE,\n AgentSkill,\n AgentSubAgent,\n} from \"../types\";\n\n/**\n * Sub-agent that researches and profiles individual people into\n * structured markdown. Produces one profile per person, maintains\n * cross-references to related companies, software, and meeting notes,\n * and enqueues downstream research issues for companies and software\n * products surfaced during profiling (handed off to the\n * `company-profile` and `software-profile` bundles).\n *\n * The prompt deliberately avoids hardcoded domains, companies, or source\n * projects. Consumers configure the person-role taxonomy scope, output\n * paths, cross-reference targets, and refresh cadence via the skill\n * invocation and by extending the rule in their own `agentConfig.rules`.\n */\nconst peopleProfileAnalystSubAgent: AgentSubAgent = {\n name: \"people-profile-analyst\",\n description:\n \"Researches an individual person (colleague, customer contact, vendor contact, partner contact, industry expert, or connector) from public sources and produces a structured markdown profile cross-linked to companies, software, and meeting notes, then enqueues downstream `company:research` and `software:research` issues for unprofiled companies and software products surfaced during profiling. One person per session, tracked by people:* GitHub issue labels.\",\n model: AGENT_MODEL.POWERFUL,\n maxTurns: 80,\n platforms: { cursor: { exclude: true } },\n prompt: [\n \"# People Profile Analyst Agent\",\n \"\",\n \"You research a single person from public sources and write a\",\n \"structured markdown profile. Each profile cycle runs across a small\",\n \"sequence of GitHub issues — one per phase — and produces a single\",\n \"profile file on disk plus cross-references to related entities\",\n \"(companies, software, meeting notes) already tracked elsewhere in\",\n \"the project.\",\n \"\",\n \"This agent is **domain-neutral**. It makes no assumptions about what\",\n \"the consuming project sells, which industry it serves, or which\",\n \"people matter to it. All domain-specific vocabulary, output\",\n \"locations, cross-reference targets, and profile-template overrides\",\n \"come from the invoking issue body or the consuming project's\",\n \"configuration.\",\n \"\",\n \"Follow your project's shared agent conventions (`AGENTS.md`,\",\n \"`CLAUDE.md`, or equivalent) for all commit, branch, and PR rules.\",\n \"\",\n \"---\",\n \"\",\n ...PROJECT_CONTEXT_READER_SECTION,\n \"## Design Principles\",\n \"\",\n \"1. **One person per session.** Never profile two people in a single\",\n \" session, even if they came up together (e.g. co-founders).\",\n \"2. **Public sources only.** Use the person's own public writing,\",\n \" company bios, conference talks, public interviews, and similar\",\n \" public material. Do not attempt to access gated or paywalled\",\n \" content unless the invoking issue body explicitly authorizes it.\",\n \"3. **Filesystem durability.** The profile file is the deliverable. It\",\n \" is committed to disk before the profile issue closes. Downstream\",\n \" phases read from disk — never rely on session memory.\",\n \"4. **Generic over specific.** No hardcoded role types, taxonomies, or\",\n \" relationship assumptions. Use the generic person-role taxonomy\",\n \" below and let consuming projects override it.\",\n \"5. **Cite everything.** Every non-trivial factual claim in the\",\n \" profile must carry a source citation (URL plus access date).\",\n \"6. **Respect privacy.** Profile only public, professional information.\",\n \" Never capture home addresses, personal phone numbers, family\",\n \" details, health information, or other private data even when\",\n \" encountered in public sources.\",\n \"7. **Cross-reference, don't duplicate.** When the profile mentions a\",\n \" company, software product, or meeting already tracked by the\",\n \" consuming project, link to the existing artifact rather than\",\n \" duplicating its content.\",\n \"8. **Follow-up, don't widen scope.** If the session turns up adjacent\",\n \" research questions (a significant employer worth profiling, a\",\n \" software product the person created or leads), emit a follow-up\",\n \" issue rather than expanding the profile beyond its scope.\",\n \" Companies are handed off to the `company-profile` bundle via\",\n \" `company:research` issues; software products are handed off to\",\n \" the `software-profile` bundle via `software:research` issues.\",\n \" Meeting notes remain link-only — this agent never creates\",\n \" meeting-research issues.\",\n \"\",\n \"---\",\n \"\",\n \"## Person Role Taxonomy\",\n \"\",\n \"Pick exactly one role per person profile. The taxonomy is\",\n \"deliberately generic — consuming projects override it via\",\n \"`agentConfig.rules` if they need a domain-specific refinement.\",\n \"\",\n \"| Role | Use for |\",\n \"|------|---------|\",\n \"| `colleague` | People inside your own organization worth tracking (teammates, cross-functional partners, leadership). |\",\n \"| `customer-contact` | Named individuals at existing or prospective customer accounts. |\",\n \"| `vendor-contact` | Named individuals at vendors, suppliers, or software providers you depend on. |\",\n \"| `partner-contact` | Named individuals at strategic, channel, or integration partners. |\",\n \"| `industry-expert` | Analysts, researchers, journalists, or well-known practitioners whose work shapes the market. |\",\n \"| `connector` | People who primarily provide introductions, referrals, or access across networks — advisors, investors acting as connectors, community hubs. |\",\n \"\",\n \"If the person plausibly fits two roles, prefer the one that reflects\",\n \"the **reason the profile was requested**, and note the secondary\",\n \"role in the profile body.\",\n \"\",\n \"---\",\n \"\",\n \"## State Machine Overview\",\n \"\",\n \"```\",\n \"┌───────────────────┐ ┌──────────────────────┐ ┌────────────────────┐\",\n \"│ 1. RESEARCH │────▶│ 2. DRAFT PROFILE │────▶│ 3. FOLLOWUP │\",\n \"│ Collect public │ │ Write the structured │ │ Cross-link existing│\",\n \"│ sources into a │ │ markdown profile to │ │ artifacts; enqueue │\",\n \"│ bounded notes │ │ the configured path │ │ company/software │\",\n \"│ file │ │ │ │ research issues │\",\n \"└───────────────────┘ └──────────────────────┘ └────────────────────┘\",\n \"```\",\n \"\",\n \"**Issue labels encode the phase:**\",\n \"\",\n \"| Label | Phase | Session work |\",\n \"|-------|-------|-------------|\",\n \"| `people:research` | 1. Research | Gather public sources. Write a bounded research-notes file. Create the draft issue. |\",\n \"| `people:draft` | 2. Draft | Read the research notes. Write the structured profile to `<PROFILES_DIR>`. Create the followup issue if warranted. |\",\n \"| `people:followup` | 3. Followup | Read the profile. Update cross-references to existing companies, software, and meeting notes. Enqueue `company:research` and `software:research` issues for unprofiled, genuinely-relevant entities surfaced in the profile. |\",\n \"\",\n \"All issues also carry `type:people-profile` and a `status:*` label.\",\n \"\",\n \"**Issue count per person cycle:** 1 research + 1 draft + 0–1 followup =\",\n \"**2–3 sessions**. The followup phase is skipped when the profile did\",\n \"not surface any cross-references worth linking and no companies or\",\n \"software products warrant downstream research.\",\n \"\",\n \"**Shortened paths:**\",\n \"- Research phase determines the person is out of scope (not\",\n \" relevant, insufficient public material) → research issue closes\",\n \" with a justification and no downstream issues are created → **1 session**.\",\n \"- Short profile with no cross-references and no downstream\",\n \" candidates → **2 sessions**.\",\n \"\",\n \"---\",\n \"\",\n \"## Configurable Paths\",\n \"\",\n \"The pipeline uses these placeholders. Consuming projects override the\",\n \"defaults by passing paths in the `/profile-person` skill invocation\",\n \"or by extending this rule in their own `agentConfig.rules`.\",\n \"\",\n \"| Placeholder | Meaning | Default |\",\n \"|-------------|---------|---------|\",\n \"| `<PEOPLE_ROOT>` | Root folder for person profiles | `docs/people/` |\",\n \"| `<PROFILES_DIR>` | Final person profile files | `<PEOPLE_ROOT>/profiles/` |\",\n \"| `<NOTES_DIR>` | Research-notes files from Phase 1 | `<PEOPLE_ROOT>/notes/` |\",\n \"| `<PERSON_SLUG>` | Short kebab-case slug identifying the person | derived from the person's name |\",\n \"| `<COMPANIES_DIR>` | Where existing company profiles live (for cross-references and duplicate detection during followup) | `docs/companies/profiles/` |\",\n \"| `<SOFTWARE_DIR>` | Where existing software profiles live (for cross-references and duplicate detection during followup) | `docs/software/profiles/` |\",\n \"| `<MEETINGS_DIR>` | Where meeting notes live (for cross-references) | `docs/meetings/` |\",\n \"\",\n \"If `docs/project-context.md` specifies a different people-research\",\n \"tree or cross-reference target, prefer that. Otherwise fall back to\",\n \"the defaults above. Cross-reference directories are read-only — this\",\n \"agent never writes into them.\",\n \"\",\n \"---\",\n \"\",\n \"## Refresh Cadence\",\n \"\",\n \"Profiles go stale. A person changes jobs, publishes new work, or\",\n \"shifts focus. The pipeline supports a configurable refresh cadence:\",\n \"\",\n \"- **Default cadence:** 180 days from the profile's `date` frontmatter.\",\n \"- **Override:** the invoking issue body may specify a `refresh_days: N`\",\n \" field, or the consuming project may set a project-wide default in\",\n \" `docs/project-context.md`.\",\n \"\",\n \"When the `/profile-person` skill is invoked for a slug that already\",\n \"has a profile:\",\n \"\",\n \"- If the profile is **younger** than the refresh cadence, the skill\",\n \" exits with a message pointing to the existing profile. Pass\",\n \" `force: true` in the issue body to refresh anyway.\",\n \"- If the profile is **older** than the refresh cadence, the pipeline\",\n \" proceeds in update-in-place mode: Phase 2 edits the existing file,\",\n \" preserves its slug, and bumps the `date` frontmatter.\",\n \"\",\n \"Refresh mode never changes the profile's role without an explicit\",\n \"override in the refresh request — role changes are material and\",\n \"warrant a human review step.\",\n \"\",\n \"---\",\n \"\",\n \"## Agent Loop\",\n \"\",\n \"Run this loop exactly once per session. Never start a second issue.\",\n \"\",\n \"1. Claim one open `type:people-profile` issue using phase priority:\",\n \" `people:research` > `people:draft` > `people:followup`.\",\n \"2. Transition `status:ready` → `status:in-progress` and create the\",\n \" branch per your project's branch-naming convention.\",\n \"3. Execute the phase handler that matches the issue's `people:*`\",\n \" label.\",\n \"4. Commit, push, open a PR (if applicable), and close the issue per\",\n \" your project's PR workflow.\",\n \"\",\n \"---\",\n \"\",\n \"## Phase 1: Research (`people:research`)\",\n \"\",\n \"**Goal:** Gather public sources into a bounded research-notes file.\",\n \"\",\n \"**Budget:** Public web search only, unless the issue body authorizes\",\n \"additional sources. Write one notes file. Do not write the profile\",\n \"in this phase.\",\n \"\",\n \"### Steps\",\n \"\",\n \"1. **Read the issue body.** It should include:\",\n \" - The person's name and primary affiliation (company) if known\",\n \" - The requested role from the taxonomy above\",\n \" - The reason the profile was requested (framing — what does the\",\n \" invoking project want to learn?)\",\n \" - Optional: `<PERSON_SLUG>` override, custom output paths,\",\n \" `refresh_days` override, `force: true` for out-of-cadence refresh\",\n \"\",\n \"2. **Derive `<PERSON_SLUG>`** if not supplied — a 2–4 word kebab-case\",\n \" summary of the person's name. Disambiguate against any existing\",\n \" slug under `<PROFILES_DIR>/` or `<NOTES_DIR>/` by appending a\",\n \" company or role qualifier (e.g. `jane-doe-acme`).\",\n \"\",\n \"3. **Check for an existing profile.** If `<PROFILES_DIR>/<PERSON_SLUG>.md`\",\n \" exists, read its `date` frontmatter and apply the refresh cadence\",\n \" rules above before proceeding.\",\n \"\",\n \"4. **Gather sources.** Prioritize in this order:\",\n \" - The person's own public writing (personal site, blog, newsletter)\",\n \" - Their current employer's bio / leadership page\",\n \" - Public conference talks, podcast appearances, and interviews\",\n \" - Public directories that the invoking issue body authorizes\",\n \" (LinkedIn, GitHub, company profiles, Crunchbase)\",\n \" - Public contributions (open-source repos, published papers)\",\n \"\",\n \"5. **Write a research-notes file** to\",\n \" `<NOTES_DIR>/<PERSON_SLUG>.notes.md`:\",\n \"\",\n \" ```markdown\",\n \" ---\",\n ' title: \"Research Notes: <person name>\"',\n \" slug: <PERSON_SLUG>\",\n \" role: <one of the taxonomy values>\",\n \" primary_company: <company name if known>\",\n \" date: YYYY-MM-DD\",\n \" parent_issue: <N>\",\n \" ---\",\n \"\",\n \" # Research Notes: <person name>\",\n \"\",\n \" ## Framing\",\n \" <why this person was requested and what to learn>\",\n \"\",\n \" ## Raw Findings\",\n \" - <finding> — source: <citation>\",\n \"\",\n \" ## Candidate Cross-References\",\n \" - **Companies mentioned:** <list of company names>\",\n \" - **Software mentioned:** <list of product names>\",\n \" - **Meetings mentioned:** <list of meeting identifiers>\",\n \"\",\n \" ## Open Questions\",\n \" <anything the notes could not answer from public sources>\",\n \"\",\n \" ## Sources\",\n \" - <source URL or file path> — <date accessed>\",\n \" ```\",\n \"\",\n \"6. **Create the `people:draft` issue** with `Depends on: #<research-issue>`.\",\n \" Its body references the notes file path, the requested role, and\",\n \" any refresh-mode flags.\",\n \"\",\n \"7. **Commit and push** the notes file. Close the research issue.\",\n \"\",\n \"---\",\n \"\",\n \"## Phase 2: Draft Profile (`people:draft`)\",\n \"\",\n \"**Goal:** Write the structured person profile from the research notes.\",\n \"\",\n \"**Budget:** No new web searches unless explicitly needed to fill a\",\n \"gap the notes flagged. Write one profile file.\",\n \"\",\n \"### Steps\",\n \"\",\n \"1. **Read the research-notes file** referenced in the issue body.\",\n \"\",\n \"2. **Check for duplicates / refresh.** If `<PROFILES_DIR>/<PERSON_SLUG>.md`\",\n \" already exists:\",\n \" - In refresh mode, open the existing file and update in place,\",\n \" preserving the slug and bumping the `date` frontmatter.\",\n \" - Otherwise, flag a naming collision and stop — never silently\",\n \" overwrite a non-trivial existing profile.\",\n \"\",\n \"3. **Write the profile** to `<PROFILES_DIR>/<PERSON_SLUG>.md` using\",\n \" the template below. All sections are required; use\",\n \" `_Not available in public sources._` when a section cannot be\",\n \" filled from the notes.\",\n \"\",\n \" ```markdown\",\n \" ---\",\n ' title: \"<person name>\"',\n \" slug: <PERSON_SLUG>\",\n \" role: <one of the taxonomy values>\",\n \" primary_company: <company name>\",\n \" date: YYYY-MM-DD\",\n \" refresh_days: <N, default 180>\",\n \" parent_issue: <N>\",\n \" notes: <NOTES_DIR>/<PERSON_SLUG>.notes.md\",\n \" ---\",\n \"\",\n \" # <person name>\",\n \"\",\n \" ## Summary\",\n \" <2–4 sentence elevator description: who they are, what they do,\",\n \" why they matter to this project>\",\n \"\",\n \" ## Classification\",\n \" - **Primary role:** <taxonomy value>\",\n \" - **Secondary role (if any):** <taxonomy value or `n/a`>\",\n \" - **Relevance to this project:** <1–2 sentences tying the person\",\n \" back to the framing from the notes>\",\n \"\",\n \" ## Current Position\",\n \" - **Company:** <primary company — link to company profile if tracked>\",\n \" - **Title:** <current title>\",\n \" - **Tenure:** <since YYYY, if known>\",\n \" - **Focus areas:** <what they work on day-to-day>\",\n \"\",\n \" ## Background\",\n \" - **Prior roles:** <short reverse-chronological list>\",\n \" - **Education / credentials:** <if publicly disclosed>\",\n \" - **Notable contributions:** <open-source, publications, talks>\",\n \"\",\n \" ## Expertise Signals\",\n \" <topics they write or speak about — each bullet cited to a public\",\n \" source>\",\n \"\",\n \" ## Positioning / Point of View\",\n \" <how they describe their own work and views — use their own\",\n \" language, cited, rather than inferred>\",\n \"\",\n \" ## Cross-References\",\n \" - **Companies:** <links to `<COMPANIES_DIR>/*.md` for companies\",\n \" already tracked by this project>\",\n \" - **Software:** <links to `<SOFTWARE_DIR>/*.md` for software\",\n \" already tracked by this project>\",\n \" - **Meetings:** <links to `<MEETINGS_DIR>/*.md` for meeting notes\",\n \" this person participated in>\",\n \"\",\n \" ## Contact Preferences\",\n \" <public channels only — company email if listed, social handles,\",\n \" speaker inquiry forms. Never private contact info.>\",\n \"\",\n \" ## Risks / Open Questions\",\n \" <what the profile could not answer; flag anything the followup\",\n \" phase should cross-reference>\",\n \"\",\n \" ## Sources\",\n \" - <source URL> — <date accessed>\",\n \" ```\",\n \"\",\n \"4. **Decide whether a followup issue is warranted.** Create a\",\n \" `people:followup` issue (depending on this draft issue) if the\",\n \" profile's Candidate Cross-References lists at least one company,\",\n \" software product, or meeting — whether or not the entity is\",\n \" already profiled. The followup phase links what exists and\",\n \" enqueues downstream research for what doesn't. Only skip the\",\n \" followup when the profile surfaced no cross-reference candidates\",\n \" at all; note this in the draft issue's closing comment.\",\n \"\",\n \"5. **Commit and push** the profile file. Close the draft issue.\",\n \"\",\n \"---\",\n \"\",\n \"## Phase 3: Followup (`people:followup`)\",\n \"\",\n \"**Goal:** Populate the profile's `## Cross-References` section with\",\n \"links to existing artifacts — companies, software, meetings — that\",\n \"the consuming project already tracks, **and** enqueue downstream\",\n \"`company:research` and `software:research` issues for unprofiled,\",\n \"genuinely-relevant companies and software products surfaced in the\",\n \"profile. Hand the candidates off to the `company-profile` and\",\n \"`software-profile` bundles so they can be researched independently.\",\n \"\",\n \"**Budget:** No new web searches. Read the candidate cross-references,\",\n \"resolve them against the configured directories, update the profile,\",\n \"and enqueue downstream research issues where warranted. Markdown\",\n \"cross-references in the profile are preserved — issue creation is\",\n \"**additive** on top of the existing cross-reference behavior.\",\n \"\",\n \"### Steps\",\n \"\",\n \"1. **Read the profile file** referenced in the issue body.\",\n \"\",\n \"2. **Resolve company cross-references.** For each company named in\",\n \" the profile's research notes or body text, look for a matching\",\n \" file under `<COMPANIES_DIR>/`. If found, link it under\",\n \" `## Cross-References > Companies` and do **not** open a\",\n \" `company:research` issue for it — the profile already exists.\",\n \"\",\n \"3. **Resolve software cross-references.** Same pattern against\",\n \" `<SOFTWARE_DIR>/`. If found, link under `## Cross-References >\",\n \" Software` and do **not** open a `software:research` issue.\",\n \"\",\n \"4. **Resolve meeting cross-references.** For meetings the person\",\n \" participated in, look for a matching file under `<MEETINGS_DIR>/`\",\n \" by date or slug. Link matches; leave TODOs otherwise. Meeting\",\n \" notes are **always link-only** — this agent never opens\",\n \" meeting-research issues.\",\n \"\",\n \"5. **Enqueue a `company:research` issue per unprofiled, genuinely-\",\n \" relevant company.** For each company named in the profile that\",\n \" has no matching file under `<COMPANIES_DIR>/`, decide whether it\",\n \" warrants a downstream company profile (see restraint guidance\",\n \" below). If so, open an issue carrying:\",\n \"\",\n \" - `type:company-profile`\",\n \" - `company:research`\",\n \" - `priority:medium`\",\n \" - `status:ready`\",\n \"\",\n \" The issue body must include:\",\n \" - A **discovery source** line naming this person profile\",\n \" (`Discovered while profiling: <person name>`)\",\n \" - A link to the person profile path (`Person profile: <PROFILES_DIR>/<PERSON_SLUG>.md`)\",\n \" - Enough identifying metadata — company name and primary domain/\",\n \" website — that the `company-profile-analyst` agent can begin\",\n \" research without revisiting this person profile\",\n \"\",\n \"6. **Enqueue a `software:research` issue per unprofiled software\",\n \" product the person has primary attribution for.** For each\",\n \" software product named in the profile with no matching file under\",\n \" `<SOFTWARE_DIR>/`, decide whether it warrants a downstream\",\n \" software profile (see restraint guidance below). If so, open an\",\n \" issue carrying:\",\n \"\",\n \" - `type:software-profile`\",\n \" - `software:research`\",\n \" - `priority:medium`\",\n \" - `status:ready`\",\n \"\",\n \" The issue body must include:\",\n \" - A **discovery source** line naming this person profile\",\n \" (`Discovered while profiling: <person name>`)\",\n \" - A link to the person profile path (`Person profile: <PROFILES_DIR>/<PERSON_SLUG>.md`)\",\n \" - Enough identifying metadata — product name and vendor (the\",\n \" company that builds or maintains the product) — that the\",\n \" `software-profile-analyst` agent can begin research without\",\n \" revisiting this person profile\",\n \"\",\n \"7. **Avoid duplicates.** Before opening a `company:research` or\",\n \" `software:research` issue, verify no existing profile or open\",\n \" research issue already covers the candidate:\",\n \"\",\n \" - Companies: check `<COMPANIES_DIR>/` for a matching profile\",\n \" file (by derived slug or by searching the directory for the\",\n \" company's name). If a profile exists, reuse it as a cross-\",\n \" reference only — **do not** open a new `company:research` issue.\",\n \" - Software: check `<SOFTWARE_DIR>/` the same way. If a profile\",\n \" exists, reuse it as a cross-reference only — **do not** open a\",\n \" new `software:research` issue.\",\n \" - Also scan open issues carrying the matching `company:research`\",\n \" or `software:research` label so this phase never re-opens\",\n \" research that is already queued.\",\n \"\",\n \"8. **Exercise restraint.** Only create downstream issues for\",\n \" entities **genuinely relevant** to the person's professional\",\n \" identity:\",\n \"\",\n \" - **Companies:** open an issue for the person's current\",\n \" employer, significant past employers (roles of real tenure or\",\n \" leadership influence), companies where they sit on the board\",\n \" or act as an advisor, and companies they co-founded. Do **not**\",\n \" open an issue for every company on their LinkedIn, short\",\n \" consulting engagements, or employers tangential to the framing\",\n \" of this profile.\",\n \" - **Software:** open an issue only for products where the person\",\n \" has **primary attribution** — creator, maintainer, lead PM,\",\n \" founding engineer, or otherwise materially influenced the\",\n \" product. Do **not** open an issue for software the person\",\n \" merely uses, endorses in passing, or lists in a stack. When\",\n \" in doubt, leave the candidate as a markdown cross-reference\",\n \" and skip the downstream issue.\",\n \"\",\n \"9. **Assume the peers are present.** This pipeline assumes the\",\n \" `company-profile` and `software-profile` bundles are enabled in\",\n \" the consuming project. If a consuming project has disabled one\",\n \" of them, flag the followup issue with `status:needs-attention`\",\n \" and list the candidates that could not be routed — never invent\",\n \" an alternative label taxonomy.\",\n \"\",\n \"10. **Cross-link** — update the profile's `## Cross-References`\",\n \" section so each company or software entry references either\",\n \" the linked profile path (for existing profiles) or the newly-\",\n \" created downstream issue number (for candidates that were\",\n \" enqueued for research).\",\n \"\",\n \"11. **Commit and push** the updated profile. Close the followup\",\n \" issue.\",\n \"\",\n \"---\",\n \"\",\n \"## Output Boundaries\",\n \"\",\n \"This agent writes **only** to:\",\n \"\",\n \"- `<NOTES_DIR>/` — research-notes files (Phase 1)\",\n \"- `<PROFILES_DIR>/` — person profiles (Phase 2, updated in Phase 3)\",\n \"\",\n \"In Phase 3, this agent also **creates `company:research` and\",\n \"`software:research` issues** for companies and software products\",\n \"surfaced in the profile that are not already tracked under\",\n \"`<COMPANIES_DIR>/` or `<SOFTWARE_DIR>/`. It never writes the\",\n \"downstream profiles themselves — those are the responsibility of the\",\n \"`company-profile-analyst` and `software-profile-analyst` agents,\",\n \"which pick up the issues this pipeline creates. Meeting notes\",\n \"remain link-only across all phases.\",\n \"\",\n \"The pipeline produces **person profiles and notes only**. Deeper\",\n \"research on companies and software products is delegated to\",\n \"downstream research pipelines via `company:research` and\",\n \"`software:research` issues — this agent never writes company\",\n \"profiles, software profiles, product evaluations, or comparative\",\n \"analyses itself. Keep this boundary clean so the people-profile\",\n \"pipeline stays generic.\",\n \"\",\n \"---\",\n \"\",\n \"## Rules\",\n \"\",\n \"- **One person per session.** Never profile two people back-to-back.\",\n \"- **Persist before closing.** Every phase must write its output file\",\n \" before closing its issue.\",\n \"- **Cite everything.** Profile claims without source citations do not\",\n \" belong in the deliverable.\",\n \"- **Respect privacy.** Never record private contact details, family\",\n \" information, or other non-professional personal data, even when\",\n \" encountered in a public source.\",\n \"- **Cross-reference, don't duplicate.** Link to existing company,\",\n \" software, and meeting artifacts rather than re-describing them.\",\n \"- **Delegate, don't duplicate.** Unprofiled companies and software\",\n \" products surfaced during profiling are handed off to the\",\n \" `company-profile` and `software-profile` bundles via\",\n \" `company:research` and `software:research` issues in Phase 3 —\",\n \" never inlined as company or software profiles in this pipeline.\",\n \"- **Check before enqueueing.** Before opening a `company:research`\",\n \" or `software:research` issue, verify no existing profile or open\",\n \" research issue already covers the candidate. Reuse existing\",\n \" profiles as cross-references rather than re-queuing research.\",\n \"- **Restrain the queue.** Only enqueue downstream research for\",\n \" companies that are a current employer, significant past employer,\",\n \" board/advisor role, or co-founded venture — not every company on\",\n \" the person's résumé. Only enqueue software research for products\",\n \" the person has **primary attribution** for (creator, maintainer,\",\n \" lead PM), not products they merely use.\",\n \"- **Meetings stay link-only.** Phase 3 never opens meeting-research\",\n \" or any other meeting-related issues. Meetings are cross-\",\n \" referenced only.\",\n \"- **Produce profiles, not requirement or evaluation documents.** Do\",\n \" not open `type:requirement` or formal evaluation issues from this\",\n \" pipeline. Follow-up research is scoped through `company:research`\",\n \" and `software:research` only.\",\n \"- **Refresh, don't fork.** When a profile exists and is past its\",\n \" cadence, update in place rather than creating a new slug.\",\n ].join(\"\\n\"),\n};\n\n/** Skill that kicks off a people profile cycle. */\nconst profilePersonSkill: AgentSkill = {\n name: \"profile-person\",\n description:\n \"Kick off a people-profile pipeline. Creates a people:research issue for the given person and dispatches Phase 1 (Research) in the people-profile-analyst agent. Phase 3 (Followup) enqueues downstream `company:research` and `software:research` issues for unprofiled, genuinely-relevant entities surfaced in the profile.\",\n disableModelInvocation: true,\n userInvocable: true,\n context: \"fork\",\n agent: \"people-profile-analyst\",\n platforms: { cursor: { exclude: true } },\n instructions: [\n \"# Profile Person\",\n \"\",\n \"Kick off a people-profile pipeline. Creates a `people:research`\",\n \"issue carrying the person's name, role, primary affiliation, and\",\n \"framing, then dispatches Phase 1 (Research) in the\",\n \"people-profile-analyst agent.\",\n \"\",\n \"## Usage\",\n \"\",\n \"/profile-person <person-name>\",\n \"\",\n \"Optional extensions in the issue body:\",\n \"- `role: <colleague | customer-contact | vendor-contact |\",\n \" partner-contact | industry-expert | connector>` — override the\",\n \" default role inference\",\n \"- `company: <name>` — primary company affiliation if not obvious\",\n \" from the name\",\n \"- `framing: <text>` — why this profile was requested and what to learn\",\n \"- `slug: <kebab-case>` — override the derived person slug\",\n \"- `refresh_days: <N>` — override the default 180-day refresh cadence\",\n \"- `force: true` — refresh even if the profile is younger than the\",\n \" cadence window\",\n \"- `sources: <list>` — additional authorized sources beyond public web\",\n \"\",\n \"## Default Paths\",\n \"\",\n \"If the project has no override in `docs/project-context.md` or\",\n \"`agentConfig.rules`, outputs land under:\",\n \"\",\n \"- `docs/people/notes/<slug>.notes.md`\",\n \"- `docs/people/profiles/<slug>.md`\",\n \"\",\n \"Cross-references are resolved against:\",\n \"\",\n \"- `docs/companies/profiles/`\",\n \"- `docs/software/profiles/`\",\n \"- `docs/meetings/`\",\n \"\",\n \"## Steps\",\n \"\",\n \"1. Create a `people:research` issue with `type:people-profile`,\",\n \" `priority:medium`, and `status:ready`. Body must include the\",\n \" person's name, selected role, primary company, framing, and any\",\n \" overrides.\",\n \"2. Execute Phase 1 (Research) of the people-profile-analyst agent.\",\n \"3. Phase 1 creates the `people:draft` issue. Phase 2 may create a\",\n \" `people:followup` issue. Each downstream issue declares its\",\n \" `Depends on:` predecessor.\",\n \"\",\n \"## Output\",\n \"\",\n \"- A research-notes file under the project's notes directory\",\n \"- A single person profile under the profiles directory\",\n \"- Cross-references to existing companies, software, and meetings\",\n \" tracked elsewhere in the project\",\n \"- `company:research` issues for unprofiled companies surfaced in\",\n \" the profile (handed off to the `company-profile` bundle)\",\n \"- `software:research` issues for software products the person has\",\n \" primary attribution for (handed off to the `software-profile`\",\n \" bundle)\",\n \"- This pipeline produces **person profiles only** — it does not\",\n \" write company profiles, software profiles, meeting notes, or any\",\n \" other downstream artifacts itself.\",\n ].join(\"\\n\"),\n};\n\n/**\n * People-profile bundle — enabled by default.\n *\n * Consuming projects can disable it with\n * `excludeBundles: [\"people-profile\"]`. `appliesWhen` always returns\n * `true` per the operating-system directive that bundles assume peers\n * are present — in Phase 3 this bundle hands work off to\n * `company-profile` (via `company:research`) and `software-profile`\n * (via `software:research`).\n *\n * Ships a sub-agent (`people-profile-analyst`), a user-invocable skill\n * (`/profile-person`), and `type:people-profile` plus `people:*` phase\n * labels.\n */\nexport const peopleProfileBundle: AgentRuleBundle = {\n name: \"people-profile\",\n description:\n \"People research and profiling pipeline: research, draft profile, followup. Enabled by default; domain-neutral; filesystem-durable between phases. Cross-references existing companies, software, and meeting notes, and Phase 3 (Followup) hands unprofiled, genuinely-relevant companies and software products off to the `company-profile` and `software-profile` bundles via `company:research` and `software:research` issues.\",\n appliesWhen: () => true,\n rules: [\n {\n name: \"people-profile-workflow\",\n description:\n \"Describes the 3-phase people-profile pipeline, the people:* label taxonomy, the cross-reference model, and the boundary against downstream research agents.\",\n scope: AGENT_RULE_SCOPE.ALWAYS,\n content: [\n \"# People Profile Workflow\",\n \"\",\n \"Use `/profile-person <person-name>` to kick off a person\",\n \"research and profiling pipeline. The pipeline runs in up to 3\",\n \"phases — research, draft, followup — each tracked by its own\",\n \"GitHub issue labeled `people:research`, `people:draft`, or\",\n \"`people:followup`. All issues carry `type:people-profile`.\",\n \"\",\n \"The pipeline produces **person profiles only**. Deeper research\",\n \"on companies and software products surfaced while profiling is\",\n \"delegated to the `company-profile` and `software-profile`\",\n \"bundles via `company:research` and `software:research` issues\",\n \"opened during Phase 3 (Followup). Meeting notes remain link-\",\n \"only — the pipeline never creates meeting-research issues.\",\n \"\",\n \"See the `people-profile-analyst` agent definition for full\",\n \"workflow details, default paths, the person-role taxonomy, the\",\n \"refresh cadence rules, and phase-by-phase instructions.\",\n ].join(\"\\n\"),\n platforms: {\n cursor: { exclude: true },\n },\n tags: [\"workflow\"],\n },\n ],\n skills: [profilePersonSkill],\n subAgents: [peopleProfileAnalystSubAgent],\n labels: [\n {\n name: \"type:people-profile\",\n color: \"0E8A16\",\n description:\n \"Work that produces or maintains a person profile or its research notes\",\n },\n {\n name: \"people:research\",\n color: \"C5DEF5\",\n description:\n \"Phase 1: gather public sources about a person into a research-notes file\",\n },\n {\n name: \"people:draft\",\n color: \"BFDADC\",\n description:\n \"Phase 2: write the structured person profile from research notes\",\n },\n {\n name: \"people:followup\",\n color: \"D4C5F9\",\n description:\n \"Phase 3: cross-link the profile to existing companies, software, and meeting notes, and enqueue follow-up research issues for unprofiled companies and software products\",\n },\n ],\n};\n","import { relative } from \"path\";\nimport { Component, Project, YamlFile } from \"projen\";\nimport { ValueOf } from \"type-fest\";\n\n/**\n * Predefined minimum release age values in minutes.\n */\nexport const MINIMUM_RELEASE_AGE = {\n ZERO_DAYS: 0,\n ONE_HOUR: 60,\n SIX_HOURS: 360,\n TWELVE_HOURS: 720,\n ONE_DAY: 1440,\n TWO_DAYS: 2880,\n THREE_DAYS: 4320,\n FOUR_DAYS: 5760,\n FIVE_DAYS: 7200,\n SIX_DAYS: 8640,\n ONE_WEEK: 10080,\n};\n\nexport interface PnpmWorkspaceOptions {\n /**\n * Filename for the pnpm workspace file. This should probably never change.\n *\n * @default \"pnpm-workspace.yaml\"\n */\n readonly fileName?: string;\n\n /**\n * To reduce the risk of installing compromised packages, you can delay the\n * installation of newly published versions. In most cases, malicious releases\n * are discovered and removed from the registry within an hour.\n *\n * minimumReleaseAge defines the minimum number of minutes that must pass\n * after a version is published before pnpm will install it. This applies to\n * all dependencies, including transitive ones.\n *\n * Note: this should match depsUpgradeOptions.cooldown in the project config.\n *\n * See: https://pnpm.io/settings#minimumreleaseage\n *\n * @default MINIMUM_RELEASE_AGE.ONE_DAY\n */\n readonly minimumReleaseAge?: ValueOf<typeof MINIMUM_RELEASE_AGE>;\n\n /**\n * If you set minimumReleaseAge but need certain dependencies to always\n * install the newest version immediately, you can list them under\n * minimumReleaseAgeExclude. The exclusion works by package name and applies\n * to all versions of that package.\n *\n * @default - no exclusions (empty array)\n *\n * See: https://pnpm.io/settings#minimumreleaseageexclude\n */\n readonly minimumReleaseAgeExclude?: Array<string>;\n\n /**\n * A list of package names that are allowed to execute \"preinstall\",\n * \"install\", and/or \"postinstall\" scripts during installation. Only the\n * packages listed in this array will be able to run those lifecycle scripts.\n * If onlyBuiltDependenciesFile and neverBuiltDependencies are omitted, this\n * configuration option will default to blocking all install scripts.\n *\n * You may restrict allowances to specific versions (and lists of versions\n * using a disjunction with ||). When versions are specified, only those\n * versions of the package may run lifecycle scripts:\n *\n * See: https://pnpm.io/settings#onlybuiltdependencies\n *\n * @default none (empty array)\n */\n readonly onlyBuiltDependencies?: Array<string>;\n\n /**\n * A list of package names that are NOT allowed to execute \"preinstall\",\n * \"install\", and/or \"postinstall\" scripts during installation and will not\n * warn or ask to be executed.\n *\n * This is useful when you want to hide the warning because you know the\n * lifecycle scripts are not needed.\n *\n * https://pnpm.io/settings#ignoredbuiltdependencies\n *\n * @default none (empty array)\n */\n readonly ignoredBuiltDependencies?: Array<string>;\n\n /**\n * Additional subproject paths to include in the workspace packages array.\n * These will be combined with any subprojects discovered via projen's\n * project.subprojects property. Paths should be relative to the project root.\n *\n * @default none (empty array)\n */\n readonly subprojects?: Array<string>;\n\n /**\n * Catalog of reusable dependency version ranges.\n *\n * The catalog allows you to define dependency versions as reusable constants\n * that can be referenced in package.json files using the catalog: protocol.\n *\n * Example:\n * ```yaml\n * catalog:\n * react: ^18.0.0\n * typescript: ^5.0.0\n * ```\n *\n * Then in package.json:\n * ```json\n * {\n * \"dependencies\": {\n * \"react\": \"catalog:react\"\n * }\n * }\n * ```\n *\n * @default undefined (not included in output)\n *\n * See: https://pnpm.io/pnpm-workspace_yaml#catalog\n */\n readonly defaultCatalog?: { [key: string]: string };\n\n /**\n * Named catalogs of reusable dependency version ranges.\n *\n * Multiple named catalogs with arbitrarily chosen names can be configured under the namedCatalogs key.\n *\n * Example:\n * ```yaml\n * namedCatalogs:\n * frontend:\n * react: ^18.0.0\n * typescript: ^5.0.0\n * backend:\n * express: ^4.18.0\n * ```\n *\n * Then in package.json:\n * ```json\n * {\n * \"dependencies\": {\n * \"react\": \"catalog:frontend/react\"\n * }\n * }\n * ```\n *\n * @default undefined (not included in output)\n *\n * See: https://pnpm.io/catalogs\n */\n readonly namedCatalogs?: {\n [catalogName: string]: { [dependencyName: string]: string };\n };\n}\n\nexport class PnpmWorkspace extends Component {\n /**\n * Get the pnpm workspace component of a project. If it does not exist,\n * return undefined.\n *\n * @param project\n * @returns\n */\n public static of(project: Project): PnpmWorkspace | undefined {\n const isDefined = (c: Component): c is PnpmWorkspace =>\n c instanceof PnpmWorkspace;\n return project.root.components.find(isDefined);\n }\n\n /**\n * Filename for the pnpm workspace file.\n */\n public readonly fileName: string;\n\n /**\n * To reduce the risk of installing compromised packages, you can delay the\n * installation of newly published versions. In most cases, malicious releases\n * are discovered and removed from the registry within an hour.\n *\n * minimumReleaseAge defines the minimum number of minutes that must pass\n * after a version is published before pnpm will install it. This applies to\n * all dependencies, including transitive ones.\n *\n * Note: this should match depsUpgradeOptions.cooldown in the project config.\n *\n * See: https://pnpm.io/settings#minimumreleaseage\n */\n public minimumReleaseAge: ValueOf<typeof MINIMUM_RELEASE_AGE>;\n\n /**\n * If you set minimumReleaseAge but need certain dependencies to always\n * install the newest version immediately, you can list them under\n * minimumReleaseAgeExclude. The exclusion works by package name and applies\n * to all versions of that package.\n *\n * See: https://pnpm.io/settings#minimumreleaseageexclude\n */\n public minimumReleaseAgeExclude: Array<string>;\n\n /**\n * A list of package names that are allowed to execute \"preinstall\",\n * \"install\", and/or \"postinstall\" scripts during installation. Only the\n * packages listed in this array will be able to run those lifecycle scripts.\n * If onlyBuiltDependenciesFile and neverBuiltDependencies are omitted, this\n * configuration option will default to blocking all install scripts.\n *\n * You may restrict allowances to specific versions (and lists of versions\n * using a disjunction with ||). When versions are specified, only those\n * versions of the package may run lifecycle scripts:\n *\n * See: https://pnpm.io/settings#onlybuiltdependencies\n */\n public onlyBuiltDependencies: Array<string>;\n\n /**\n * A list of package names that are NOT allowed to execute \"preinstall\",\n * \"install\", and/or \"postinstall\" scripts during installation and will not\n * warn or ask to be executed.\n *\n * This is useful when you want to hide the warning because you know the\n * lifecycle scripts are not needed.\n *\n * https://pnpm.io/settings#ignoredbuiltdependencies\n */\n public ignoredBuiltDependencies: Array<string>;\n\n /**\n * Additional subproject paths to include in the workspace packages array.\n * These will be combined with any subprojects discovered via projen's\n * project.subprojects property.\n */\n public subprojects: Array<string>;\n\n /**\n * Default catalog of reusable dependency version ranges.\n *\n * The default catalog is used to define dependency versions as reusable constants\n * that can be referenced in package.json files using the catalog: protocol.\n *\n * See:https://pnpm.io/catalogs\n */\n public defaultCatalog?: { [key: string]: string };\n\n /**\n * Named catalogs of reusable dependency version ranges.\n *\n * Multiple named catalogs with arbitrarily chosen names can be configured under the namedCatalogs key.\n *\n * See: https://pnpm.io/catalogs\n */\n public namedCatalogs?: {\n [catalogName: string]: { [dependencyName: string]: string };\n };\n\n constructor(project: Project, options: PnpmWorkspaceOptions = {}) {\n super(project);\n\n /***************************************************************************\n *\n * CLEAR package,json\n *\n * It appears that if ANY pnpm settings exist in the package.json file, all\n * of the setting in the pnpm-workspace.yaml file are ignored. so we need to\n * clear out anything that was placed into the package.json file.\n *\n **************************************************************************/\n\n project.tryFindObjectFile(\"package.json\")?.addDeletionOverride(\"pnpm\");\n\n /***************************************************************************\n * \n * Setup pnpm-workspace.yaml file.\n * \n * Now that the package.json file is cleared of any pnpm settings, we can\n * safely write settings to the pnpm-workspace.yaml file.\n * \n **************************************************************************\n\n /**\n * Set filename to default if not provided.\n */\n this.fileName = options.fileName ?? \"pnpm-workspace.yaml\";\n\n /**\n * Set minimum release age; default ONE_DAY when not provided.\n */\n this.minimumReleaseAge =\n options.minimumReleaseAge ?? MINIMUM_RELEASE_AGE.ONE_DAY;\n\n /**\n * Set minimum release age exclude to empty array if not provided\n */\n this.minimumReleaseAgeExclude = options.minimumReleaseAgeExclude\n ? [\"@codedrifters/*\", ...options.minimumReleaseAgeExclude]\n : [\"@codedrifters/*\"];\n\n /**\n * Set only built dependencies to empty array if not provided\n */\n this.onlyBuiltDependencies = options.onlyBuiltDependencies\n ? options.onlyBuiltDependencies\n : [];\n\n /**\n * Set ignored built dependencies to empty array if not provided\n */\n this.ignoredBuiltDependencies = options.ignoredBuiltDependencies\n ? options.ignoredBuiltDependencies\n : [];\n\n /**\n * Store additional subproject paths if provided\n */\n this.subprojects = options.subprojects ?? [];\n\n /**\n * Store catalog if provided\n */\n this.defaultCatalog = options.defaultCatalog;\n\n /**\n * Store named catalogs if provided\n */\n this.namedCatalogs = options.namedCatalogs;\n\n /**\n * In case that this file is in a package, don't package it.\n */\n project.addPackageIgnore(this.fileName);\n\n /**\n * Write pnpm workspace file\n */\n new YamlFile(this.project, this.fileName, {\n obj: () => {\n const pnpmConfig: any = {};\n const packages = new Array<string>();\n\n /**\n * Add projen subprojects to the packages array.\n */\n for (const subproject of project.subprojects) {\n // grab the relative out directory\n packages.push(relative(this.project.outdir, subproject.outdir));\n }\n\n /**\n * Add additional subproject paths provided via options.\n * Use a Set to deduplicate paths to avoid including the same\n * subproject multiple times.\n */\n const packageSet = new Set(packages);\n for (const subprojectPath of this.subprojects) {\n packageSet.add(subprojectPath);\n }\n\n /**\n * Convert back to array if we added any additional paths\n */\n if (this.subprojects.length > 0) {\n packages.length = 0;\n packages.push(...packageSet);\n }\n\n /**\n * Set minimum release age.\n */\n pnpmConfig.minimumReleaseAge = this.minimumReleaseAge;\n\n /**\n * Set minimum release age exclude if any are provided.\n */\n if (this.minimumReleaseAgeExclude.length > 0) {\n pnpmConfig.minimumReleaseAgeExclude = this.minimumReleaseAgeExclude;\n }\n\n /**\n * Set only built dependencies if any are provided.\n */\n if (this.onlyBuiltDependencies.length > 0) {\n pnpmConfig.onlyBuiltDependencies = this.onlyBuiltDependencies;\n }\n\n /**\n * Set ignored built dependencies if any are provided.\n */\n if (this.ignoredBuiltDependencies.length > 0) {\n pnpmConfig.ignoreBuiltDependencies = this.ignoredBuiltDependencies;\n }\n\n /**\n * Set default catalog if provided.\n */\n if (\n this.defaultCatalog &&\n Object.keys(this.defaultCatalog).length > 0\n ) {\n pnpmConfig.catalog = this.defaultCatalog;\n }\n\n /**\n * Set named catalogs if provided.\n */\n if (this.namedCatalogs && Object.keys(this.namedCatalogs).length > 0) {\n pnpmConfig.namedCatalogs = this.namedCatalogs;\n }\n\n /**\n * Return the final pnpm config object.\n */\n return {\n ...(packages.length > 0 ? { packages } : {}),\n ...(pnpmConfig ? { ...pnpmConfig } : {}),\n };\n },\n });\n }\n}\n\n/**\n * @deprecated Use `MINIMUM_RELEASE_AGE` instead. This alias will be removed in a future major release.\n */\nexport const MIMIMUM_RELEASE_AGE = MINIMUM_RELEASE_AGE;\n","import { Project } from \"projen/lib\";\nimport { PnpmWorkspace } from \"../../pnpm/pnpm-workspace\";\nimport { AgentRuleBundle } from \"../agent-config-options\";\nimport { AGENT_RULE_SCOPE } from \"../types\";\nimport { hasComponent } from \"./utils\";\n\n/**\n * PNPM bundle — auto-detected when the PnpmWorkspace component is present.\n */\nexport const pnpmBundle: AgentRuleBundle = {\n name: \"pnpm\",\n description: \"PNPM workspace rules and dependency management conventions\",\n appliesWhen: (project: Project) => hasComponent(project, PnpmWorkspace),\n rules: [\n {\n name: \"pnpm-workspace\",\n description: \"PNPM workspace and dependency management conventions\",\n scope: AGENT_RULE_SCOPE.FILE_PATTERN,\n filePatterns: [\"package.json\", \"pnpm-workspace.yaml\", \"pnpm-lock.yaml\"],\n content: [\n \"# PNPM Workspace Conventions\",\n \"\",\n \"## Package Management\",\n \"\",\n \"- Use **PNPM** for package management\",\n \"- Workspace configuration in `pnpm-workspace.yaml`\",\n \"- Dependencies managed through Projen, not directly in `package.json`\",\n \"- **Always use workspace dependencies** (`workspace:*` or `workspace:^`) for packages within this monorepo\",\n \"- Never use published NPM versions of internal packages; always reference the local workspace version\",\n \"\",\n \"## Dependency Management\",\n \"\",\n \"**DO:**\",\n \"- Configure dependencies in Projen configuration files (`.projenrc.ts` or `projenrc/*.ts`)\",\n \"- Add dependencies to `deps`, `devDeps`, or `peerDeps` arrays in project configuration\",\n '- Use catalog dependencies when available (e.g., `\"aws-cdk-lib@catalog:\"`)',\n \"- Ask the user to run `npx projen` and `pnpm install` after updating dependency configuration\",\n \"\",\n \"**DO NOT:**\",\n \"- Run `npm install some-package`\",\n \"- Run `pnpm add some-package`\",\n \"- Run `yarn add some-package`\",\n \"- Manually edit `package.json` dependencies\",\n \"\",\n \"Manual package installation creates conflicts with Projen-managed files.\",\n ].join(\"\\n\"),\n tags: [\"workflow\"],\n },\n ],\n};\n","import { AgentRuleBundle } from \"../agent-config-options\";\nimport { PROJECT_CONTEXT_READER_SECTION } from \"./project-context\";\nimport {\n AGENT_MODEL,\n AGENT_RULE_SCOPE,\n AgentSkill,\n AgentSubAgent,\n} from \"../types\";\n\n/*******************************************************************************\n *\n * PR Reviewer sub-agent — verifies a PR against its linked issue's\n * acceptance criteria and orchestrates approve / squash-merge / cleanup.\n *\n ******************************************************************************/\n\nconst prReviewerSubAgent: AgentSubAgent = {\n name: \"pr-reviewer\",\n description:\n \"Reviews a pull request against its linked issue's acceptance criteria, then enables squash auto-merge or comments with findings\",\n model: AGENT_MODEL.POWERFUL,\n maxTurns: 40,\n platforms: { cursor: { exclude: true } },\n prompt: [\n \"# PR Reviewer Agent\",\n \"\",\n \"You review a single pull request in **{{repository.owner}}/{{repository.name}}**\",\n \"against its linked issue's acceptance criteria, verify code quality and\",\n \"convention compliance, and then either enable squash auto-merge or leave\",\n \"a review comment with findings. You handle exactly **one PR per session**\",\n \"unless invoked from the multi-PR loop skill (`/review-prs`), in which case\",\n \"you process each eligible PR in turn.\",\n \"\",\n \"---\",\n \"\",\n ...PROJECT_CONTEXT_READER_SECTION,\n \"## Phase 1: Identify the PR\",\n \"\",\n \"If a PR number was provided in your instructions, use that. Otherwise stop\",\n \"and report that you need a PR number — do not pick one yourself.\",\n \"\",\n \"## Phase 1.5: Pre-flight Eligibility Filter\",\n \"\",\n \"Before spending turns on a full review, run a cheap eligibility check:\",\n \"\",\n \"```bash\",\n \"gh pr view <pr-number> --json number,title,body,headRefName,mergeable,mergeStateStatus,statusCheckRollup\",\n \"```\",\n \"\",\n \"The PR is **eligible** only when **all** of the following hold:\",\n \"\",\n '1. `mergeable == \"MERGEABLE\"` (no merge conflicts).',\n \"2. No **failing** required checks in `statusCheckRollup` — CI must be\",\n \" green or still pending. Any `FAILURE`, `TIMED_OUT`, `CANCELLED`, or\",\n \" `ERROR` conclusion on a required check disqualifies the PR.\",\n \"3. The PR body contains a linked issue via one of the closing keywords:\",\n \" `Closes #N`, `Fixes #N`, or `Resolves #N` (case-insensitive).\",\n \"\",\n \"If **any** check fails, post a short comment explaining the reason and\",\n \"stop. Do not proceed to full review.\",\n \"\",\n \"```bash\",\n \"gh pr comment <pr-number> --body '<reason>'\",\n \"```\",\n \"\",\n \"Typical reasons:\",\n \"\",\n \"- `Not reviewable: merge conflicts — please rebase onto the default branch.`\",\n \"- `Not reviewable: required CI check <name> is failing.`\",\n \"- `Not reviewable: PR body is missing a linked issue (Closes #N / Fixes #N / Resolves #N).`\",\n \"\",\n \"## Phase 2: Gather Context\",\n \"\",\n \"```bash\",\n \"gh pr view <pr-number> --json number,title,body,headRefName,baseRefName,isDraft,state,labels,reviews\",\n \"gh pr diff <pr-number>\",\n \"gh pr checks <pr-number>\",\n \"```\",\n \"\",\n \"Extract the linked issue number from the PR body using the closing keywords\",\n \"(`Closes #N`, `Fixes #N`, or `Resolves #N`) identified in Phase 1.5.\",\n \"\",\n \"Then fetch the linked issue:\",\n \"\",\n \"```bash\",\n \"gh issue view <issue-number>\",\n \"```\",\n \"\",\n \"## Phase 3: Compare Diff to Acceptance Criteria\",\n \"\",\n \"Read the issue body for an **Acceptance Criteria** (or equivalent) section.\",\n \"Build a checklist from it. For each item:\",\n \"\",\n \"1. Locate the changes in the diff that satisfy it.\",\n \"2. Mark it as `met`, `partial`, or `missing`.\",\n \"3. Record the specific files / functions / tests that provide evidence.\",\n \"\",\n \"Also evaluate:\",\n \"\",\n \"- **Convention compliance** — PR title uses a conventional commit prefix,\",\n \" body includes a closing keyword, branch name follows project conventions\",\n \"- **Test coverage** — new or changed behavior has tests\",\n \"- **CI status** — `gh pr checks` reports all required checks passing\",\n \"- **Scope creep** — diff stays within the issue's stated scope\",\n \"\",\n \"## Phase 4: Decide and Act\",\n \"\",\n \"### If all acceptance criteria are met and CI is green\",\n \"\",\n \"Enable squash auto-merge with branch deletion. This queues the merge to\",\n \"happen once required checks pass; no separate approval review is needed.\",\n \"\",\n \"```bash\",\n \"gh pr merge <pr-number> --auto --squash --delete-branch \\\\\",\n \" --subject '<conventional-commit-title>' \\\\\",\n \" --body '<extended-description>'\",\n \"```\",\n \"\",\n \"The squash-merge subject should follow conventional commit format (e.g.\",\n \"`feat(scope): description`). The body should bullet the changes and end\",\n \"with `Closes #<issue-number>`.\",\n \"\",\n \"### If any criterion is missing, partial, or CI is failing\",\n \"\",\n \"Post a plain comment (not a formal review block) with grouped findings:\",\n \"\",\n \"```bash\",\n \"gh pr comment <pr-number> --body '<grouped findings>'\",\n \"```\",\n \"\",\n \"Group findings by severity (**Blocking** / **Suggested** / **Nitpick**).\",\n \"For each blocking finding, cite the unmet acceptance criterion and the\",\n \"file or function the gap lives in. Do **not** merge, and do **not** push\",\n \"any commits to the PR's branch.\",\n \"\",\n \"Rationale for using a plain comment rather than `gh pr review\",\n \"--request-changes`: it is lighter-weight, doesn't require the author to\",\n \"dismiss a formal review, and composes cleanly with the multi-PR loop.\",\n \"\",\n \"## Phase 5: Branch Cleanup and Issue Closure Verification\",\n \"\",\n \"Auto-merge may not be immediate. Poll the PR state up to 10 times, waiting\",\n \"30 seconds between polls:\",\n \"\",\n \"```bash\",\n \"gh pr view <pr-number> --json state --jq '.state'\",\n \"```\",\n \"\",\n \"- **`MERGED`** — clean up locally **and** verify the linked issue closed:\",\n \" ```bash\",\n \" git checkout {{repository.defaultBranch}}\",\n \" git pull origin {{repository.defaultBranch}}\",\n \" git fetch --prune origin\",\n \" git branch -d <branch-name> 2>/dev/null || git branch -D <branch-name> 2>/dev/null || true\",\n \" ```\",\n \" Transition the linked issue to `status:done` (replaces whichever of\",\n \" `status:ready-for-review` or `status:in-progress` it was carrying):\",\n \" ```bash\",\n \" gh issue edit <issue-number> \\\\\",\n ' --remove-label \"status:ready-for-review\" \\\\',\n ' --remove-label \"status:in-progress\" \\\\',\n ' --add-label \"status:done\"',\n \" ```\",\n \" Then check the linked issue state:\",\n \" ```bash\",\n \" gh issue view <issue-number> --json state --jq '.state'\",\n \" ```\",\n \" If the issue is **not** `CLOSED`, close it explicitly (this covers\",\n \" malformed or missing closing keywords on the merge commit):\",\n \" ```bash\",\n \" gh issue close <issue-number> --reason completed\",\n \" gh issue comment <issue-number> --body 'PR #<pr-number> merged. Closing issue.'\",\n \" ```\",\n \"- **`CLOSED` (not merged)** — leave the branch in place; report the closure.\",\n \"- **Still `OPEN`** — auto-merge is pending; report and stop without deleting.\",\n \"\",\n \"---\",\n \"\",\n \"## Output Format\",\n \"\",\n \"Return a structured report:\",\n \"\",\n \"```\",\n \"PR #<number> — <title>\",\n \"Linked issue: #<issue-number>\",\n \"Verdict: AUTO_MERGE_ENABLED | NEEDS_CHANGES | INELIGIBLE | BLOCKED\",\n \"\",\n \"Acceptance criteria:\",\n \" [x] <criterion> — <evidence>\",\n \" [~] <criterion> — partial: <gap>\",\n \" [ ] <criterion> — missing\",\n \"\",\n \"Findings:\",\n \" - Blocking: <items>\",\n \" - Suggested: <items>\",\n \" - Nitpick: <items>\",\n \"\",\n \"Action taken: <enable-auto-merge | commented-on-the-pr | none>\",\n \"Branch state: <merged | open | closed>\",\n \"Issue state: <closed | open>\",\n \"```\",\n \"\",\n \"---\",\n \"\",\n \"## Rules\",\n \"\",\n \"1. **One PR per session** when invoked directly (`/review-pr`). When\",\n \" invoked from the multi-PR loop (`/review-prs`), process every eligible\",\n \" PR in turn.\",\n \"2. **Never merge without a linked issue.** If the PR body has no\",\n \" `Closes #N` / `Fixes #N` / `Resolves #N`, comment and stop.\",\n \"3. **Never merge with failing CI.** Even if every criterion is met,\",\n \" block on red checks.\",\n \"4. **Never bypass review conventions.** Always use `--squash`, `--auto`,\",\n \" and `--delete-branch` for merges. Do not force-merge.\",\n \"5. **Do not implement code.** You review, decide, and orchestrate. If\",\n \" the PR needs changes, comment and stop.\",\n \"6. **Never push commits to the PR's branch.** If the PR needs changes,\",\n \" comment and stop — do not attempt to fix it yourself. The PR author\",\n \" owns the branch; pushing to someone else's branch is out of scope.\",\n \"7. **In loop mode (`/review-prs`), never stop early.** If any review\",\n \" fails, comment and move to the next PR. Only abort the loop on a\",\n \" fatal error (e.g. `gh` auth failure, network outage).\",\n \"8. **Follow CLAUDE.md conventions** for all `git` and `gh` operations.\",\n ].join(\"\\n\"),\n};\n\n/*******************************************************************************\n *\n * /review-pr skill — user-invocable entry point for a single PR.\n *\n ******************************************************************************/\n\nconst reviewPrSkill: AgentSkill = {\n name: \"review-pr\",\n description:\n \"Review a single pull request against its linked issue's acceptance criteria, then enable squash auto-merge or comment with findings\",\n disableModelInvocation: true,\n userInvocable: true,\n context: \"fork\",\n agent: \"pr-reviewer\",\n platforms: { cursor: { exclude: true } },\n instructions: [\n \"# Review Pull Request\",\n \"\",\n \"Run a full PR review against the linked issue's acceptance criteria,\",\n \"then either enable squash auto-merge or post a findings comment.\",\n \"\",\n \"## Usage\",\n \"\",\n \"/review-pr <pr-number>\",\n \"\",\n \"## What This Skill Does\",\n \"\",\n \"1. Runs a pre-flight eligibility filter (mergeable, CI not failing, has linked issue)\",\n \"2. Fetches the PR, its diff, CI status, and the linked issue\",\n \"3. Builds a checklist from the issue's acceptance criteria\",\n \"4. Compares the diff against each criterion\",\n \"5. Verifies PR conventions (title, closing keyword, branch name)\",\n \"6. Verifies CI is green\",\n \"7. **If all checks pass:** enables squash auto-merge (with `--delete-branch`)\",\n \"8. **If any check fails:** posts a findings comment via `gh pr comment`\",\n \"9. After merge, verifies the linked issue is closed and closes it if not\",\n \"10. Cleans up the local branch after merge\",\n \"\",\n \"## Input\",\n \"\",\n \"Provide the PR number to review. The skill resolves the linked issue from\",\n \"the PR body (`Closes #N` / `Fixes #N` / `Resolves #N`).\",\n \"\",\n \"## Output\",\n \"\",\n \"A structured report covering verdict, per-criterion status, findings\",\n \"grouped by severity, the action taken, and the final branch / issue state.\",\n \"\",\n \"## Composability\",\n \"\",\n \"This skill is generic and can be composed with the `github-workflow`\",\n \"bundle. The reviewer never implements code and never pushes to the PR\",\n \"branch — it only reviews, decides, and orchestrates merge or comment.\",\n ].join(\"\\n\"),\n};\n\n/*******************************************************************************\n *\n * /review-prs skill — loops over every eligible open PR in the repo.\n *\n ******************************************************************************/\n\nconst reviewPrsSkill: AgentSkill = {\n name: \"review-prs\",\n description:\n \"Loop over every eligible open pull request in the repository and review each one through the full pipeline\",\n disableModelInvocation: true,\n userInvocable: true,\n context: \"fork\",\n agent: \"pr-reviewer\",\n platforms: { cursor: { exclude: true } },\n instructions: [\n \"# Review All Eligible Pull Requests\",\n \"\",\n \"Run the pr-reviewer pipeline over every eligible open PR in\",\n \"**{{repository.owner}}/{{repository.name}}**, one after another, until\",\n \"the eligible queue is empty.\",\n \"\",\n \"## Usage\",\n \"\",\n \"/review-prs\",\n \"\",\n \"## What This Skill Does\",\n \"\",\n \"### Step 1: Enumerate open PRs\",\n \"\",\n \"```bash\",\n \"gh pr list --json number,title,body,headRefName,mergeable,mergeStateStatus,statusCheckRollup --limit 50\",\n \"```\",\n \"\",\n \"### Step 2: Filter to eligible PRs\",\n \"\",\n \"A PR is **eligible** when all of the following hold:\",\n \"\",\n '1. `state == \"OPEN\"` (implicit from `gh pr list`).',\n '2. `mergeable == \"MERGEABLE\"` (no conflicts).',\n \"3. No required check in `statusCheckRollup` has a failing conclusion\",\n \" (`FAILURE`, `TIMED_OUT`, `CANCELLED`, `ERROR`). CI green or still\",\n \" pending is fine.\",\n \"4. The PR body contains a linked issue (`Closes #N` / `Fixes #N` /\",\n \" `Resolves #N`, case-insensitive).\",\n \"\",\n \"Drop any PR that fails the filter from the queue. Do not comment on\",\n \"them from this skill — the individual `/review-pr` invocation handles\",\n \"the inline rejection comment when run on a specific PR.\",\n \"\",\n \"### Step 3: Process each eligible PR\",\n \"\",\n \"For every eligible PR, invoke the full pr-reviewer pipeline\",\n \"(Phases 1 through 5) as if `/review-pr <number>` had been called\",\n \"directly:\",\n \"\",\n \"- Gather context (diff, checks, linked issue)\",\n \"- Compare diff to acceptance criteria\",\n \"- Decide and act (enable auto-merge **or** post findings comment)\",\n \"- Verify branch / issue cleanup after merge\",\n \"\",\n \"Continue to the next PR after each one completes. Never stop the loop\",\n \"early because a single PR's review failed — comment and move on.\",\n \"\",\n \"### Step 4: Stop when the queue is empty\",\n \"\",\n \"When no eligible PRs remain, emit a final summary listing every PR\",\n \"processed and the verdict for each, then stop.\",\n \"\",\n \"## Output\",\n \"\",\n \"Per-PR structured report (same shape as `/review-pr`), followed by a\",\n \"one-line-per-PR summary at the end:\",\n \"\",\n \"```\",\n \"Summary:\",\n \" PR #<n>: <verdict>\",\n \" PR #<n>: <verdict>\",\n \" ...\",\n \"Total processed: <count>\",\n \"```\",\n \"\",\n \"## Failure Handling\",\n \"\",\n \"Only abort the loop on a fatal error (e.g. `gh` authentication failure,\",\n \"network outage). A failed review for an individual PR is not fatal —\",\n \"comment on that PR and continue with the next.\",\n ].join(\"\\n\"),\n};\n\n/*******************************************************************************\n *\n * Bundle definition — opt-in. Consumers must include via `includeBundles`\n * (or it auto-detects through the appliesWhen below). No hardcoded\n * domain-specific content.\n *\n ******************************************************************************/\n\nexport const prReviewBundle: AgentRuleBundle = {\n name: \"pr-review\",\n description:\n \"Pull request review workflow: verifies PRs against their linked issues' acceptance criteria and orchestrates squash-merge, single or looped over all eligible PRs\",\n\n // Default-apply: the PR review workflow is safe to include everywhere,\n // and keeping review/merge policy centralised in the pr-reviewer agent\n // means consumers get consistent behaviour out of the box. Consumers can\n // still exclude it explicitly via `excludeBundles` if desired.\n appliesWhen: () => true,\n\n rules: [\n {\n name: \"pr-review-workflow\",\n description:\n \"Describes the /review-pr and /review-prs skills and their delegation to the pr-reviewer sub-agent\",\n scope: AGENT_RULE_SCOPE.ALWAYS,\n content: [\n \"# PR Review Workflow\",\n \"\",\n \"Two skills are available, both backed by the same `pr-reviewer`\",\n \"sub-agent:\",\n \"\",\n \"- **`/review-pr <pr-number>`** — review a single targeted PR.\",\n \"- **`/review-prs`** — loop over every eligible open PR in the\",\n \" repository and review each one in turn.\",\n \"\",\n \"The `pr-reviewer` sub-agent:\",\n \"\",\n \"1. Runs a pre-flight eligibility filter (mergeable, CI not failing,\",\n \" has a linked issue). Ineligible PRs get a short comment and are\",\n \" skipped.\",\n \"2. Fetches the PR, its diff, CI status, and the linked issue\",\n \"3. Builds a checklist from the issue's acceptance criteria\",\n \"4. Verifies the diff satisfies each criterion and that CI is green\",\n \"5. **Enables squash auto-merge** (with `--delete-branch`) when all\",\n \" checks pass — no explicit approval review\",\n \"6. **Comments with grouped findings** when any check fails (plain\",\n \" `gh pr comment`, not a formal `--request-changes` review)\",\n \"7. After a successful merge, verifies the linked issue is closed\",\n \" and closes it explicitly if the merge commit did not\",\n \"8. Cleans up the local branch after merge\",\n \"\",\n \"The reviewer **never** implements code and **never** pushes commits\",\n \"to a PR's branch — it only reviews, decides, and orchestrates merge\",\n \"or comment. In loop mode, a failed review for one PR never stops\",\n \"the loop; the reviewer comments and moves on. See the `pr-reviewer`\",\n \"agent definition for the full phase-by-phase contract.\",\n ].join(\"\\n\"),\n platforms: {\n cursor: { exclude: true },\n },\n tags: [\"workflow\"],\n },\n ],\n\n skills: [reviewPrSkill, reviewPrsSkill],\n subAgents: [prReviewerSubAgent],\n};\n","import { Project } from \"projen/lib\";\nimport { AgentRuleBundle } from \"../agent-config-options\";\nimport { AGENT_RULE_SCOPE } from \"../types\";\nimport { hasDep } from \"./utils\";\n\n/**\n * Projen bundle — auto-detected when `projen` is in dependencies.\n */\nexport const projenBundle: AgentRuleBundle = {\n name: \"projen\",\n description: \"Projen conventions, synthesis workflow, .projenrc.ts patterns\",\n appliesWhen: (project: Project) => hasDep(project, \"projen\"),\n rules: [\n {\n name: \"development-commands\",\n description:\n \"Projen development commands for building, testing, linting, and validating changes\",\n scope: AGENT_RULE_SCOPE.ALWAYS,\n content: [\n \"# Development Commands\",\n \"\",\n \"This project uses Projen to manage configuration and Turborepo to orchestrate builds across the monorepo. Run all commands from the **repository root** unless otherwise noted.\",\n \"\",\n \"## Synthesizing Projen Configuration\",\n \"\",\n \"After modifying any file in `projenrc/` or `.projenrc.ts`, regenerate project files:\",\n \"\",\n \"```sh\",\n \"npx projen\",\n \"pnpm install\",\n \"```\",\n \"\",\n \"Both steps are required — `npx projen` regenerates files, `pnpm install` updates the lockfile to match.\",\n \"\",\n \"## Building\",\n \"\",\n \"**Full monorepo build** (compile + test + package, all sub-packages via Turborepo):\",\n \"\",\n \"```sh\",\n \"pnpm build:all\",\n \"```\",\n \"\",\n \"**Root project only** (synthesize + compile + lint):\",\n \"\",\n \"```sh\",\n \"pnpm build\",\n \"```\",\n \"\",\n \"**Single sub-package** (compile only):\",\n \"\",\n \"```sh\",\n \"pnpm --filter @codedrifters/<package> compile\",\n \"```\",\n \"\",\n \"Replace `<package>` with `configulator`, `constructs`, or `utils`.\",\n \"\",\n \"## Testing\",\n \"\",\n \"**Run tests for a single sub-package:**\",\n \"\",\n \"```sh\",\n \"pnpm --filter @codedrifters/<package> test\",\n \"```\",\n \"\",\n \"This runs ESLint + Vitest for the specified package.\",\n \"\",\n \"**Run only Vitest (skip lint) in a sub-package:**\",\n \"\",\n \"```sh\",\n \"cd packages/@codedrifters/<package>\",\n \"pnpm exec vitest run\",\n \"```\",\n \"\",\n \"**Run a specific test file:**\",\n \"\",\n \"```sh\",\n \"cd packages/@codedrifters/<package>\",\n \"pnpm exec vitest run src/path/to/file.test.ts\",\n \"```\",\n \"\",\n \"## Linting\",\n \"\",\n \"**Lint the root project:**\",\n \"\",\n \"```sh\",\n \"pnpm eslint\",\n \"```\",\n \"\",\n \"**Lint a single sub-package:**\",\n \"\",\n \"```sh\",\n \"pnpm --filter @codedrifters/<package> eslint\",\n \"```\",\n \"\",\n \"## Resetting Build Artifacts\",\n \"\",\n \"**Reset everything** (all packages + root):\",\n \"\",\n \"```sh\",\n \"pnpm reset:all\",\n \"```\",\n \"\",\n \"**Reset root only:**\",\n \"\",\n \"```sh\",\n \"pnpm reset\",\n \"```\",\n \"\",\n \"## Validating Changes Are Complete\",\n \"\",\n \"After finishing implementation work, validate that changes are correct by running the appropriate commands depending on what was changed:\",\n \"\",\n \"1. **Projen config changes** (`projenrc/`, `.projenrc.ts`):\",\n \" - Run `npx projen` then `pnpm install`\",\n \" - Verify no unexpected generated file changes with `git diff`\",\n \"\",\n \"2. **Source code changes** (in a sub-package):\",\n \" - Compile: `pnpm --filter @codedrifters/<package> compile`\",\n \" - Test: `pnpm --filter @codedrifters/<package> test`\",\n \"\",\n \"3. **Changes spanning multiple packages**:\",\n \" - Run `pnpm build:all` to validate the full monorepo build\",\n \"\",\n \"4. **Root-level changes** (projenrc, root config):\",\n \" - Run `pnpm build` to validate root synthesis + compilation + lint\",\n \"\",\n \"## Command Reference\",\n \"\",\n \"| Task | Command |\",\n \"|------|---------|\",\n \"| Synthesize projen | `npx projen` |\",\n \"| Install deps | `pnpm install` |\",\n \"| Full monorepo build | `pnpm build:all` |\",\n \"| Root build only | `pnpm build` |\",\n \"| Compile one package | `pnpm --filter @codedrifters/<pkg> compile` |\",\n \"| Test one package | `pnpm --filter @codedrifters/<pkg> test` |\",\n \"| Lint one package | `pnpm --filter @codedrifters/<pkg> eslint` |\",\n \"| Lint root | `pnpm eslint` |\",\n \"| Reset all artifacts | `pnpm reset:all` |\",\n ].join(\"\\n\"),\n tags: [\"workflow\"],\n },\n {\n name: \"agent-rules-customization\",\n description:\n \"How to customize agent rules for this repo via the Projen project definition\",\n scope: AGENT_RULE_SCOPE.FILE_PATTERN,\n filePatterns: [\n \"projenrc/**/*.ts\",\n \".projenrc.ts\",\n \".claude/rules/*.md\",\n \".cursor/rules/*.mdc\",\n \"CLAUDE.md\",\n ],\n content: [\n \"# Customizing Agent Rules\",\n \"\",\n \"Agent rules for Claude and Cursor are **generated** by configulator's `AgentConfig` component. The generated output files (`.claude/rules/`, `.cursor/rules/`, `CLAUDE.md`) must not be edited directly — they are overwritten on every `npx projen` run.\",\n \"\",\n \"## Adding Repo-Specific Rules\",\n \"\",\n \"Rules that only apply to this repository should be added to the `agentConfig.rules` array in the Projen project definition (`.projenrc.ts` or `projenrc/*.ts`):\",\n \"\",\n \"```typescript\",\n \"agentConfig: {\",\n \" rules: [\",\n \" {\",\n \" name: 'my-repo-rule',\",\n \" description: 'What this rule does',\",\n \" scope: AGENT_RULE_SCOPE.ALWAYS, // or FILE_PATTERN with filePatterns\",\n \" content: '# My Rule\\\\n\\\\n- Guideline 1\\\\n- Guideline 2',\",\n \" },\",\n \" ],\",\n \"}\",\n \"```\",\n \"\",\n \"## Extending Existing Bundle Rules\",\n \"\",\n \"To append repo-specific content to a rule provided by a configulator bundle (without replacing it), use `agentConfig.ruleExtensions`:\",\n \"\",\n \"```typescript\",\n \"agentConfig: {\",\n \" ruleExtensions: {\",\n \" 'typescript-conventions': '## Additional Guidelines\\\\n\\\\n- My custom guideline',\",\n \" },\",\n \"}\",\n \"```\",\n \"\",\n \"## After Any Change\",\n \"\",\n \"Run `npx projen` then `pnpm install` to regenerate the output files.\",\n ].join(\"\\n\"),\n tags: [\"workflow\"],\n },\n {\n name: \"projen-conventions\",\n description: \"Projen configuration patterns and best practices\",\n scope: AGENT_RULE_SCOPE.FILE_PATTERN,\n filePatterns: [\"projenrc/**/*.ts\", \".projenrc.ts\"],\n content: [\n \"# Projen Conventions\",\n \"\",\n \"## Configuration Management\",\n \"\",\n \"- **Never edit generated files** (`package.json`, `tsconfig.json`, etc. marked with `// ~~ Generated by projen`)\",\n \"- Edit Projen configuration in:\",\n \" - `.projenrc.ts` (root)\",\n \" - `projenrc/*.ts` (package-specific)\",\n \"- After making Projen changes, run `npx projen` to synthesize\",\n \"\",\n \"## Workspace Dependencies\",\n \"\",\n \"When adding dependencies between packages in a monorepo:\",\n \"\",\n '- Use the workspace protocol: `project.addDeps(\"@org/sibling-pkg@workspace:*\")`',\n \"- This ensures the local version is always resolved, not a registry version\",\n '- For dev dependencies: `project.addDevDeps(\"@org/sibling-pkg@workspace:*\")`',\n \"\",\n \"## The `configureMyProject` Pattern\",\n \"\",\n \"Each package should expose a `configureMyProject(options)` factory function that creates and configures its Projen project:\",\n \"\",\n \"```typescript\",\n \"export function configureMyProject(\",\n \" options: MyProjectOptions,\",\n \"): TypeScriptProject {\",\n \" const project = new TypeScriptProject({\",\n \" ...options,\",\n \" // package-specific defaults\",\n \" });\",\n \"\",\n \" // Attach components, configure rules, etc.\",\n \" return project;\",\n \"}\",\n \"```\",\n \"\",\n \"This pattern keeps `.projenrc.ts` clean and makes package configuration reusable and testable.\",\n \"\",\n \"## Custom Projen Components\",\n \"\",\n \"All custom components must extend `Component` from Projen and use a static `.of()` factory for discovery:\",\n \"\",\n \"```typescript\",\n \"export class MyComponent extends Component {\",\n \" public static of(project: Project): MyComponent | undefined {\",\n \" const isDefined = (c: Component): c is MyComponent =>\",\n \" c instanceof MyComponent;\",\n \" return project.components.find(isDefined);\",\n \" }\",\n \"\",\n \" constructor(project: Project, options: MyComponentOptions) {\",\n \" super(project);\",\n \" // Implementation\",\n \" }\",\n \"}\",\n \"```\",\n \"\",\n \"## Component Authoring\",\n \"\",\n \"- Export project types and utilities from `index.ts`\",\n \"- Follow Projen's component lifecycle patterns\",\n \"- Use `merge` from `ts-deepmerge` for deep merging configuration objects\",\n \"- Components should be reusable and configurable; use TypeScript interfaces for component options\",\n \"- Provide sensible defaults while allowing customization\",\n \"- Document public APIs with minimal JSDoc; put extended documentation in markdown\",\n \"\",\n \"## Dependencies\",\n \"\",\n \"- Dependencies managed through Projen configuration, not directly in `package.json`\",\n '- Use catalog dependencies when available (e.g., `\"projen\": \"catalog:\"`)',\n \"- Peer dependencies for shared libraries (e.g., `constructs`, `projen`, `aws-cdk-lib`)\",\n '- Use workspace protocol for internal packages: `\"@org/pkg@workspace:*\"`',\n ].join(\"\\n\"),\n tags: [\"workflow\"],\n },\n ],\n};\n","import { AgentRuleBundle } from \"../agent-config-options\";\nimport { PROJECT_CONTEXT_MAINTAINER_SECTION } from \"./project-context\";\nimport {\n AGENT_MODEL,\n AGENT_RULE_SCOPE,\n AgentSkill,\n AgentSubAgent,\n} from \"../types\";\n\n/**\n * Sub-agent that discovers requirement gaps from BCM model documents,\n * competitive analysis, product roadmaps, and meeting extracts, then\n * produces deduplicated scan reports and requirement proposals for the\n * downstream `requirements-writer` agent. Trace-phase issues carry the\n * `req:write` label so the writer bundle picks them up automatically.\n */\nconst requirementsAnalystSubAgent: AgentSubAgent = {\n name: \"requirements-analyst\",\n description:\n \"Discovers requirement gaps from BCM model docs, competitive analysis, product docs, and meeting extracts. Produces scan reports and proposals for the downstream requirements-writer agent. Runs through a 3-phase pipeline (scan → draft → trace), one phase per session, tracked by req:* GitHub issue labels.\",\n model: AGENT_MODEL.POWERFUL,\n maxTurns: 80,\n platforms: { cursor: { exclude: true } },\n prompt: [\n \"# Requirements Analyst Agent\",\n \"\",\n \"Dedicated agent loop for discovering requirement gaps from BCM (Business\",\n \"Capability Model) documents, product docs, and competitive analysis — then\",\n \"creating well-formed requirement issues for the downstream\",\n \"`requirements-writer` agent to draft. Designed for scheduled execution\",\n \"downstream of the BCM writer and company research agents.\",\n \"\",\n \"Follow your project's shared agent conventions (`AGENTS.md`,\",\n \"`CLAUDE.md`, or equivalent) for all commit, branch, and PR rules.\",\n \"\",\n \"---\",\n \"\",\n ...PROJECT_CONTEXT_MAINTAINER_SECTION,\n \"## Design Principles\",\n \"\",\n \"1. **Discover, don't write.** This agent identifies *what requirements are\",\n \" missing*. The `requirements-writer` agent writes the actual documents.\",\n \" The boundary keeps this agent fast and the `requirements-writer`\",\n \" authoritative.\",\n \"2. **Trace everything.** Every discovered gap links to the source that\",\n \" revealed it (a BCM model doc, competitive analysis, product doc, or\",\n \" meeting extract).\",\n \"3. **Respect the taxonomy.** Route every discovered requirement to the\",\n \" correct BCM category (FR, BR, NFR, SEC, DR, INT, OPS, UX, MT, ADR, TR)\",\n \" using the disambiguation rules in the requirements-writer skill.\",\n \"4. **Deduplicate.** Before creating an issue, check whether a requirement\",\n \" already exists or an issue is already open for it.\",\n \"\",\n \"---\",\n \"\",\n \"## State Machine Overview\",\n \"\",\n \"Requirements synthesis flows through **3 phases**:\",\n \"\",\n \"```\",\n \"┌──────────────┐ ┌──────────────┐ ┌──────────────┐\",\n \"│ 1. SCAN │────▶│ 2. DRAFT │────▶│ 3. TRACE │\",\n \"│ Read docs, │ │ Write gap │ │ Create GH │\",\n \"│ identify │ │ report with │ │ issues and │\",\n \"│ gaps, check │ │ requirement │ │ update src │\",\n \"│ for dupes │ │ proposals │ │ docs with │\",\n \"│ │ │ │ │ traceability│\",\n \"└──────────────┘ └──────────────┘ └──────────────┘\",\n \"```\",\n \"\",\n \"**Issue labels encode the phase:**\",\n \"\",\n \"| Label | Phase | Session work |\",\n \"|-------|-------|-------------|\",\n \"| `req:scan` | 1. Scan | Read source docs, identify potential requirement gaps, check against existing requirements and open issues, write deduplicated scan report |\",\n \"| `req:draft` | 2. Draft | Write gap report with proposed requirements |\",\n \"| `req:trace` | 3. Trace | Create GitHub issues for each proposed requirement and update source documents with traceability notes |\",\n \"\",\n \"All issues also carry `type:requirement` and a `status:*` label.\",\n \"\",\n \"**Issue count per scan cycle:** 1 scan + 1 draft + 1 trace = **3 sessions**.\",\n \"\",\n \"**Shortened paths:**\",\n \"- No gaps found after scan → skip draft and trace → **1 session**\",\n \"- No source docs need traceability updates → still **3 sessions** (trace\",\n \" handles both issue creation and doc updates)\",\n \"\",\n \"---\",\n \"\",\n \"## Configurable Paths\",\n \"\",\n \"Projects adopting this bundle must define these paths in their agent\",\n \"configuration (`agentConfig.rules` extension or project-level docs):\",\n \"\",\n \"| Placeholder | Meaning | Typical value |\",\n \"|-------------|---------|---------------|\",\n \"| `<BCM_DOCS_ROOT>` | Root of BCM model docs (capability models) | `src/content/docs/concepts/` |\",\n \"| `<COMPETITIVE_ROOT>` | Competitive analysis docs | `src/content/docs/business-strategy/competitive/` |\",\n \"| `<PRODUCT_ROOT>` | Product roadmap / entity taxonomy | `src/content/docs/product/` |\",\n \"| `<MEETINGS_ROOT>` | Meeting extracts | `src/content/docs/research/meetings/` |\",\n \"| `<RESEARCH_REQUIREMENTS_ROOT>` | Scan reports and proposals | `src/content/docs/research/requirements/` |\",\n \"| `<REQUIREMENTS_ROOT>` | Final requirement documents (owned by requirements-writer) | `src/content/docs/requirements/` |\",\n \"| `<PREFIX>` | Project-specific requirement ID prefix | e.g. `VRTX`, `ACME` |\",\n \"\",\n \"If your project stores these in different locations, substitute accordingly\",\n \"wherever the phase instructions reference a path.\",\n \"\",\n \"---\",\n \"\",\n \"## Agent Loop\",\n \"\",\n \"Run this loop exactly once per session. Never start a second issue.\",\n \"\",\n \"1. Claim one open `type:requirement` issue using phase priority:\",\n \" `req:scan` > `req:draft` > `req:trace`.\",\n \"2. Transition `status:ready` → `status:in-progress` and create the branch\",\n \" per your project's branch-naming convention.\",\n \"3. Execute the phase handler that matches the issue's `req:*` label.\",\n \"4. Commit, push, open a PR (if applicable), and close the issue per your\",\n \" project's PR workflow.\",\n \"\",\n \"---\",\n \"\",\n \"## Phase 1: Scan (`req:scan`)\",\n \"\",\n \"**Goal:** Read source documents, identify where requirements are missing,\",\n \"incomplete, or contradictory, then check each potential gap against existing\",\n \"requirements and open issues to eliminate duplicates. Produces a single\",\n \"deduplicated scan report.\",\n \"\",\n \"**Budget:** Reading source docs + reading requirement registries + searching\",\n \"issues. Write one deduplicated scan output file.\",\n \"\",\n \"### Scan Sources\",\n \"\",\n \"The issue specifies which source(s) to scan. Common scan scopes:\",\n \"\",\n \"| Scope | What to read | What to look for |\",\n \"|-------|-------------|-----------------|\",\n \"| **BCM model doc** | One `{PREFIX}-NNN` doc under `<BCM_DOCS_ROOT>` | The doc's project-relevance section (commonly `## <Project> Relevance` or `## Strategic Implications`) — gaps where capabilities exist but no FR/BR/INT addresses them. Use `docs/project-context.md` to judge what is relevant. |\",\n \"| **Competitive analysis** | One `comp-*.md` doc under `<COMPETITIVE_ROOT>` | Feature comparison gaps — competitor features the product lacks requirements for |\",\n \"| **Product roadmap** | `<PRODUCT_ROOT>/prioritized-feature-roadmap.md` | Roadmap items without corresponding FRs |\",\n \"| **Entity taxonomy** | `<PRODUCT_ROOT>/entity-taxonomy.md` | Entities without CRUD requirements (FR), data requirements (DR), or security requirements (SEC) |\",\n \"| **Meeting extract** | `<MEETINGS_ROOT>/meeting-*.extract.md` | Requirements identified but not yet formalized |\",\n \"\",\n \"### Steps\",\n \"\",\n \"1. **Read the source documents** specified in the issue.\",\n \"\",\n \"2. **Identify potential gaps.** For each potential missing requirement:\",\n \" - Classify into the correct BCM category (FR, BR, NFR, SEC, DR, INT,\",\n \" OPS, UX, MT, ADR, TR)\",\n \" - Apply the disambiguation rules from the requirements-writer skill\",\n \" - Note the source that revealed the gap\",\n \" - Estimate priority based on the source context\",\n \"\",\n \"3. **Read the requirements registry.** Scan `_index.md` files in each\",\n \" `<REQUIREMENTS_ROOT>/<category>/` directory to know what already exists.\",\n \"\",\n \"4. **Search for existing issues.** For each potential gap, search open issues:\",\n \" ```bash\",\n ' gh issue list --label \"type:requirement\" --state open \\\\',\n \" --json number,title --limit 100\",\n \" ```\",\n \"\",\n \"5. **Classify each gap:**\",\n \" - **New** — no existing requirement or open issue covers this\",\n \" - **Duplicate** — an existing requirement already addresses this\",\n \" - **In progress** — an open issue already targets this\",\n \" - **Partial** — existing requirement partially covers this; note the gap\",\n \"\",\n \"6. **Write the deduplicated scan report** to:\",\n \" ```\",\n \" <RESEARCH_REQUIREMENTS_ROOT>/req-scan-<scope>-<YYYY-MM-DD>.md\",\n \" ```\",\n \"\",\n \" Format:\",\n \" ```markdown\",\n \" ---\",\n ' title: \"Requirements Scan: <scope>\"',\n \" date: YYYY-MM-DD\",\n \" parent_issue: <N>\",\n \" status: complete\",\n \" ---\",\n \"\",\n \" # Requirements Scan: <scope>\",\n \"\",\n \" ## Source Documents Reviewed\",\n \" - <path> — <brief description>\",\n \"\",\n \" ## Existing Requirements Checked\",\n \" - <category>: <count> existing docs, <count> open issues\",\n \"\",\n \" ## Identified Gaps (New)\",\n \" ### Gap 1: <Title>\",\n \" - **Category:** FR / BR / NFR / SEC / DR / INT / OPS / UX / MT / ADR / TR\",\n \" - **Source:** <path to doc + section that revealed this gap>\",\n \" - **Priority:** High / Normal / Low\",\n \" - **Rationale:** <why this requirement is needed>\",\n \" - **Duplicate check:** No existing requirement or open issue found\",\n \" - **Proposed scope:** <1-2 sentences on what the requirement should cover>\",\n \"\",\n \" ## Already Covered\",\n \" <list of potential gaps that turned out to already have requirements>\",\n \"\",\n \" ## In Progress\",\n \" <gaps that already have open issues — include issue numbers>\",\n \"\",\n \" ## Ambiguous / Needs Human Decision\",\n \" <gaps where the correct category or scope is unclear>\",\n \" ```\",\n \"\",\n \"7. **Create downstream issues based on findings:**\",\n \" - If any new gaps were identified → create `req:draft` issue\",\n \" (blocked on this issue via `Depends on: #N`).\",\n \" - If **no gaps** were found → stop (no further phases needed). Comment\",\n \" on the issue noting that no gaps were identified, and proceed directly\",\n \" to commit and push. The scan issue will be marked done with no\",\n \" downstream work needed.\",\n \"\",\n \"8. **Commit and push.**\",\n \"\",\n \"---\",\n \"\",\n \"## Phase 2: Draft (`req:draft`)\",\n \"\",\n \"**Goal:** Expand each identified gap into a requirement proposal with enough\",\n \"detail for the requirements-writer to produce a full document.\",\n \"\",\n \"**Budget:** No web searches. Reading + writing.\",\n \"\",\n \"### Steps\",\n \"\",\n \"1. **Read the scan report** from Phase 1.\",\n \"\",\n \"2. **For each gap**, write a detailed proposal:\",\n \"\",\n \" ```markdown\",\n \" ## Proposed: <PREFIX>-<NNN> — <Title>\",\n \"\",\n \" **Category:** <FR/BR/NFR/SEC/DR/INT/OPS/UX/MT/ADR/TR>\",\n \" **Priority:** <High/Normal/Low>\",\n \" **Source:** <document path and section>\",\n \"\",\n \" ### Summary\",\n \" <2-3 sentences describing what the requirement should capture>\",\n \"\",\n \" ### Draft Acceptance Criteria\",\n \" - [ ] <testable criterion 1>\",\n \" - [ ] <testable criterion 2>\",\n \" - [ ] <testable criterion 3>\",\n \"\",\n \" ### Traceability\",\n \" - **Implements:** <BR or parent requirement if applicable>\",\n \" - **Related:** <existing requirements that interact with this one>\",\n \" - **Source:** <BCM doc, competitive analysis, or meeting that revealed\",\n \" the gap — use a markdown link. If the source is a meeting note, the\",\n \" downstream requirement doc must include the same meeting as a link in\",\n \" its Traceability `Related:` list.>\",\n \"\",\n \" ### Decision Authority\",\n ' <\"Direct write\" for BR/FR/NFR/SEC/UX, or \"Proposed — needs human',\n ' decision\" for ADR/TR, or \"Mixed — defer technology choices\" for',\n \" DR/MT/INT/OPS>\",\n \"\",\n \" ### Notes for Requirements Writer\",\n \" <any context the writer should know — related ADRs, existing partial\",\n \" coverage, relevant competitive features>\",\n \" ```\",\n \"\",\n \"3. **Write the proposals** to:\",\n \" ```\",\n \" <RESEARCH_REQUIREMENTS_ROOT>/req-proposals-<scope>-<YYYY-MM-DD>.md\",\n \" ```\",\n \"\",\n \"4. **Determine next sequence numbers.** Check each target category\",\n \" directory under `<REQUIREMENTS_ROOT>/<category>/` to find the next\",\n \" available `NNN` for each proposed requirement.\",\n \"\",\n \"5. **Create the `req:trace` issue** blocked on this draft issue.\",\n \"\",\n \"6. **Commit and push.**\",\n \"\",\n \"---\",\n \"\",\n \"## Phase 3: Trace (`req:trace`)\",\n \"\",\n \"**Goal:** Create GitHub issues for each proposed requirement and update\",\n \"source documents with traceability notes indicating that requirement issues\",\n \"were created.\",\n \"\",\n \"**Budget:** No web searches. Issue creation + minor edits to source\",\n \"documents.\",\n \"\",\n \"### Steps\",\n \"\",\n \"1. **Read the proposals** from Phase 2.\",\n \"\",\n \"2. **Create requirement issues.** For each proposal:\",\n \"\",\n \" All `type:requirement` issues default to `priority:medium` (override\",\n \" only if the proposal's priority was explicitly High or Low). Each\",\n \" issue must also carry the `req:write` phase label so the downstream\",\n \" `requirements-writer` bundle picks it up.\",\n \"\",\n \" ```bash\",\n \" gh issue create \\\\\",\n ' --title \"docs(<category>): <PREFIX>-<NNN> — <title>\" \\\\',\n ' --label \"type:requirement\" --label \"req:write\" --label \"status:ready\" --label \"priority:medium\" \\\\',\n ' --body \"## Objective',\n \" Write <PREFIX>-<NNN> — <title>.\",\n \"\",\n \" ## Context\",\n \" - **Gap identified by:** requirements scan of <source>\",\n \" - **Proposals file:** <RESEARCH_REQUIREMENTS_ROOT>/req-proposals-<scope>-<date>.md\",\n \"\",\n \" ## Inputs\",\n \" - **Depends on:** (none)\",\n \" - **Read:** <RESEARCH_REQUIREMENTS_ROOT>/req-proposals-<scope>-<date>.md, <source docs>\",\n \"\",\n \" ## Acceptance Criteria\",\n \" - [ ] Requirement document follows <category> template\",\n \" - [ ] Traceability links to source BCM/competitive/product doc\",\n \" - [ ] Registry index updated\",\n \" - [ ] Decision authority rules followed (direct write vs. proposed)\",\n \"\",\n \" ## Scope Size\",\n \" small\",\n \"\",\n \" ## Output Path\",\n ' <REQUIREMENTS_ROOT>/<category>/<PREFIX>-<NNN>-<slug>.md\"',\n \" ```\",\n \"\",\n \"3. **Update source documents.** In each BCM model doc or competitive\",\n \" analysis that was scanned, add a note in the project-relevance /\",\n \" strategic-implications section (whichever heading the source doc uses)\",\n \" indicating that a requirement issue was created:\",\n \"\",\n \" ```markdown\",\n \" - Gap addressed: see [<PREFIX>-<NNN>](<relative path to requirement doc>)\",\n \" (issue #<N>)\",\n \" ```\",\n \"\",\n \"4. **Comment on the scan issue** with a summary of all issues created and\",\n \" all docs updated.\",\n \"\",\n \"5. **Commit and push.**\",\n \"\",\n \"---\",\n \"\",\n \"## Coordination with Other Agents\",\n \"\",\n \"| Direction | Agent | What |\",\n \"|-----------|-------|------|\",\n \"| Upstream | BCM Writer | Scans capability-model docs for project-relevance gaps (judged against `docs/project-context.md`) |\",\n \"| Upstream | Company Research | Scans competitive analysis for feature comparison gaps |\",\n \"| Upstream | Meeting Analyst | Scans meeting extracts for requirement proposals |\",\n \"| Downstream | `requirements-writer` | Picks up the `type:requirement` + `req:write` issues this agent creates and drafts the actual requirement document |\",\n \"\",\n \"**File boundaries:** Writes to `<RESEARCH_REQUIREMENTS_ROOT>/req-*.md` and\",\n \"minor traceability edits to `<BCM_DOCS_ROOT>` and `<COMPETITIVE_ROOT>`.\",\n \"Never writes to `<REQUIREMENTS_ROOT>/` — that is owned by the\",\n \"requirements-writer agent.\",\n \"\",\n \"---\",\n \"\",\n \"## Blocked Issues\",\n \"\",\n \"Additional block reasons specific to requirements synthesis:\",\n \"- Source document has unresolved contradictions\",\n \"- Category classification is ambiguous (needs human disambiguation)\",\n \"- Dependent BCM documents are still in draft with placeholder content\",\n \"\",\n \"---\",\n \"\",\n \"## Rules\",\n \"\",\n \"- **Discover, don't write requirements.** Create issues for the\",\n \" `requirements-writer` agent — don't write requirement documents\",\n \" directly.\",\n \"- **Deduplicate rigorously.** Check both existing docs and open issues\",\n \" before flagging a gap.\",\n \"- **Respect decision authority.** Mark ADR/TR proposals as needing human\",\n \" decision. Don't create direct-write issues for technology choices.\",\n \"- **Bidirectional traceability.** Every `req-scan-*.md` and\",\n \" `req-proposals-*.md` must include a `## Produced` section listing the\",\n \" downstream requirement issues (and eventual requirement documents) it\",\n \" spawned, as markdown links; each formal requirement document under\",\n \" `<REQUIREMENTS_ROOT>/` must include a forward link back to the scan or\",\n \" proposal that produced it.\",\n ].join(\"\\n\"),\n};\n\n/** Skill that kicks off a requirements scan. */\nconst scanRequirementsSkill: AgentSkill = {\n name: \"scan-requirements\",\n description:\n \"Kick off a requirements-analyst scan across BCM model docs, competitive analysis, product docs, or meeting extracts. Creates a req:scan issue and dispatches Phase 1.\",\n disableModelInvocation: true,\n userInvocable: true,\n context: \"fork\",\n agent: \"requirements-analyst\",\n platforms: { cursor: { exclude: true } },\n instructions: [\n \"# Scan Requirements\",\n \"\",\n \"Kick off a requirements-analyst scan cycle. Creates a `req:scan` issue\",\n \"targeted at the requested scope and dispatches Phase 1 (Scan) in the\",\n \"requirements-analyst agent.\",\n \"\",\n \"## Usage\",\n \"\",\n \"/scan-requirements <scope>\",\n \"\",\n \"Where `<scope>` is one of:\",\n \"- `bcm:<PREFIX-NNN>` — a single BCM model doc\",\n \"- `competitive:<slug>` — a single competitive analysis doc\",\n \"- `product-roadmap` — the prioritized feature roadmap\",\n \"- `entity-taxonomy` — the entity taxonomy doc\",\n \"- `meeting:<slug>` — a meeting extract\",\n \"- `all-bcm` / `all-competitive` — full sweep (long-running)\",\n \"\",\n \"## Steps\",\n \"\",\n \"1. Create a `req:scan` issue with `type:requirement`, `priority:medium`,\",\n \" and `status:ready`. Body must list the files to read and the scan scope.\",\n \"2. Execute Phase 1 (Scan) of the requirements-analyst agent.\",\n \"3. If gaps are found, a `req:draft` issue is created automatically.\",\n \"\",\n \"## Output\",\n \"\",\n \"- A `req-scan-<scope>-<YYYY-MM-DD>.md` file under the project's research\",\n \" requirements directory.\",\n \"- A `req:draft` issue if any gaps were identified.\",\n ].join(\"\\n\"),\n};\n\n/**\n * Requirements-analyst bundle — opt-in via `includeBundles: [\\\"requirements-analyst\\\"]`.\n *\n * Provides a 3-phase requirements gap-discovery pipeline (scan → draft → trace)\n * designed for projects using the BCM (Business Capability Model) framework.\n * Ships a sub-agent, a user-invocable skill, and `req:*` phase labels via the\n * bundle `labels` mechanism so consuming projects automatically pick up the\n * label taxonomy through the sync-labels workflow.\n */\nexport const requirementsAnalystBundle: AgentRuleBundle = {\n name: \"requirements-analyst\",\n description:\n \"Requirements gap-discovery agent bundle for BCM-driven projects. 3-phase pipeline (scan, draft, trace) with req:* phase labels.\",\n appliesWhen: () => true,\n rules: [\n {\n name: \"requirements-analyst-workflow\",\n description:\n \"Describes the 3-phase requirements gap-discovery pipeline, the req:* label taxonomy, and the boundary with the downstream requirements-writer agent.\",\n scope: AGENT_RULE_SCOPE.ALWAYS,\n content: [\n \"# Requirements Analyst Workflow\",\n \"\",\n \"Use `/scan-requirements <scope>` to kick off a requirements gap\",\n \"discovery cycle. The pipeline runs in 3 phases — scan, draft, trace —\",\n \"each tracked by its own GitHub issue labeled `req:scan`, `req:draft`,\",\n \"or `req:trace`. All issues carry `type:requirement`.\",\n \"\",\n \"The requirements-analyst *discovers gaps and drafts proposals*; it\",\n \"does **not** write final requirement documents. Writing is the job\",\n \"of the downstream `requirements-writer` agent (a separate bundle).\",\n \"Keep that boundary clean: proposals land under the research\",\n \"requirements directory, not under the authoritative requirements\",\n \"tree. The trace phase tags new issues with `req:write` so the\",\n \"writer bundle picks them up automatically.\",\n \"\",\n \"See the `requirements-analyst` agent definition for full workflow\",\n \"details and phase-by-phase instructions.\",\n ].join(\"\\n\"),\n platforms: {\n cursor: { exclude: true },\n },\n tags: [\"workflow\"],\n },\n ],\n skills: [scanRequirementsSkill],\n subAgents: [requirementsAnalystSubAgent],\n labels: [\n {\n name: \"type:requirement\",\n color: \"1D76DB\",\n description:\n \"Work that produces or discovers a requirement document (FR, BR, NFR, etc.)\",\n },\n {\n name: \"req:scan\",\n color: \"C5DEF5\",\n description:\n \"Phase 1: scan source docs for requirement gaps and deduplicate\",\n },\n {\n name: \"req:draft\",\n color: \"BFDADC\",\n description:\n \"Phase 2: draft requirement proposals for the requirements-writer\",\n },\n {\n name: \"req:trace\",\n color: \"D4C5F9\",\n description:\n \"Phase 3: create requirement issues and backfill traceability on source docs\",\n },\n ],\n};\n","import { AgentRuleBundle } from \"../agent-config-options\";\nimport { PROJECT_CONTEXT_READER_SECTION } from \"./project-context\";\nimport {\n AGENT_MODEL,\n AGENT_RULE_SCOPE,\n AgentSkill,\n AgentSubAgent,\n} from \"../types\";\n\n/**\n * Verbatim BR (Business Requirement) template shipped to the consuming\n * project under the requirements-writer skill's reference directory.\n */\nconst TEMPLATE_BR = `---\ntitle: \"BR-NNN: [Business Requirement Title]\"\n---\n\n# BR-NNN: [Business Requirement Title]\n\n## Metadata\n\n| Field | Value |\n|---|---|\n| **ID** | BR-NNN |\n| **Status** | Draft |\n| **Tier** | [Platform · Industry · Customer Workflow · Consumer Application] |\n| **Implementor** | [Consortium Member · Customer · TBD — required for Customer Workflow and Consumer Application tiers. When Consortium Member, link to org profile] |\n| **Customer** | [Link to customer org profile if this requirement originated from or applies to a specific customer. Optional for Platform/Industry tiers, expected for Customer Workflow/Consumer Application tiers] |\n| **Priority** | [Critical / High / Medium / Low] |\n| **Owner** | [Name or role responsible for this requirement] |\n| **Created** | YYYY-MM-DD |\n| **Last Updated** | YYYY-MM-DD |\n\n## Business Need\n\nA clear statement of the business problem or opportunity this requirement addresses. Focus on the \"why\" — what pain point exists, what opportunity we're capturing, or what strategic goal this supports.\n\n## Stakeholders\n\n| Stakeholder | Role | Interest |\n|---|---|---|\n| [Name/Group] | [Their role] | [What they care about regarding this requirement] |\n\n## Success Metrics\n\nDefine how we'll know this requirement has been successfully met. Metrics should be specific and measurable.\n\n| Metric | Target | Measurement Method |\n|---|---|---|\n| [e.g., Onboarding completion rate] | [e.g., > 80% within 7 days] | [e.g., Analytics funnel tracking] |\n\n## Scope\n\n### In Scope\n\nWhat is explicitly included in this business requirement.\n\n### Out of Scope\n\nWhat is explicitly excluded — important for preventing scope creep and setting expectations.\n\n## Assumptions\n\nList assumptions that underpin this requirement. Flag any that carry risk if they turn out to be wrong.\n\n- [Assumption 1]\n- [Assumption 2]\n\n## Constraints\n\nBusiness-level constraints that bound this requirement (budget, timeline, regulatory, organizational).\n\n- [Constraint 1]\n- [Constraint 2]\n\n## Dependencies\n\nOther business requirements, external factors, or organizational decisions this requirement depends on.\n\n- [Dependency 1]\n- [Dependency 2]\n\n## Traceability\n\n- **Decomposes into:** [FR-NNN](../functional/FR-NNN-slug.md), [FR-NNN](../functional/FR-NNN-slug.md)\n- **Constrained by:** [NFR-NNN](../non-functional/NFR-NNN-slug.md)\n- **Related:** [SEC-NNN](../security/SEC-NNN-slug.md)\n- **Depends on (cross-tier):** [XX-NNN](../category/XX-NNN-slug.md) — [platform/industry requirement this depends on]\n- **Enables (cross-tier):** [XX-NNN](../category/XX-NNN-slug.md) — [customer-workflow/consumer-app requirement this enables]\n\n## Open Items\n\n### Identified Gaps\n\n[Document any missing functionality, unhandled edge cases, or incomplete aspects. Number each item and assign a priority (P0/P1/P2/P3). Call out interdependencies with other open items. If none, write \"None identified.\"]\n\n1. **[Gap title]** \\`[P0-P3]\\`\n [Description of what's missing and why it matters.]\n → [Depends on / Blocks]: [XX-NNN Open Item #N](../category/XX-NNN-slug.md#open-items) (if applicable)\n\n### Follow-up Questions\n\n[Document anything ambiguous or where the motivation/reasoning cannot be confidently inferred. Number each item and assign a priority. If none, write \"None identified.\"]\n\n1. **[Question title]** \\`[P0-P3]\\`\n [The question, with context on why the answer matters.]\n → [Depends on / Blocks]: [XX-NNN Open Item #N](../category/XX-NNN-slug.md#open-items) (if applicable)\n\n### Contradictions & Inconsistencies\n\n[Document any conflicts with other requirements, code behavior, or documentation. Number each item and assign a priority. If none, write \"None identified.\"]\n\n1. **[Contradiction title]** \\`[P0-P3]\\`\n [Description of the conflict and what needs to be resolved.]\n → [Depends on / Blocks]: [XX-NNN Open Item #N](../category/XX-NNN-slug.md#open-items) (if applicable)\n\n## Revision History\n\n| Date | Author | Change |\n|---|---|---|\n| YYYY-MM-DD | [Name] | Initial draft |\n`;\n\n/** Verbatim FR (Functional Requirement) template. */\nconst TEMPLATE_FR = `---\ntitle: \"FR-NNN: [Functional Requirement Title]\"\n---\n\n# FR-NNN: [Functional Requirement Title]\n\n## Metadata\n\n| Field | Value |\n|---|---|\n| **ID** | FR-NNN |\n| **Status** | Draft |\n| **Tier** | [Platform · Industry · Customer Workflow · Consumer Application] |\n| **Implementor** | [Consortium Member · Customer · TBD — required for Customer Workflow and Consumer Application tiers. When Consortium Member, link to org profile] |\n| **Customer** | [Link to customer org profile if this requirement originated from or applies to a specific customer. Optional for Platform/Industry tiers, expected for Customer Workflow/Consumer Application tiers] |\n| **Priority** | [Must Have / Should Have / Could Have / Won't Have] |\n| **Owner** | [Name or role] |\n| **Created** | YYYY-MM-DD |\n| **Last Updated** | YYYY-MM-DD |\n\n## User Story\n\n**As a** [actor/role],\n**I want to** [action/capability],\n**So that** [business value/outcome].\n\n## Description\n\nA narrative description of this feature or behavior. Include enough context that someone unfamiliar with the project can understand what the system does and why it matters.\n\n## Actors\n\n| Actor | Description |\n|---|---|\n| [e.g., Registered User] | [Who they are and what access level they have] |\n\n## Preconditions\n\nConditions that must be true before this functionality can be used.\n\n- [Precondition 1]\n- [Precondition 2]\n\n## Main Flow\n\nThe primary happy-path sequence of interactions.\n\n1. [Step 1]\n2. [Step 2]\n3. [Step 3]\n\n## Alternative Flows\n\n### AF-1: [Alternative Flow Name]\n\n**Trigger:** [What causes this alternative path]\n\n1. [Step 1]\n2. [Step 2]\n\n### AF-2: [Alternative Flow Name]\n\n**Trigger:** [What causes this alternative path]\n\n1. [Step 1]\n2. [Step 2]\n\n## Exception Flows\n\n### EF-1: [Exception Flow Name]\n\n**Trigger:** [What error condition causes this]\n\n1. [Step 1 — how the system responds]\n2. [Step 2]\n\n## Acceptance Criteria\n\nSpecific, testable conditions that must be met for this requirement to be considered complete.\n\n- [ ] [Criterion 1 — stated as a concrete, verifiable condition]\n- [ ] [Criterion 2]\n- [ ] [Criterion 3]\n\n## Business Rules\n\nRules that govern the behavior described in this requirement.\n\n| Rule ID | Description |\n|---|---|\n| BIZ-01 | [e.g., Email addresses must be unique across the system] |\n| BIZ-02 | [e.g., Passwords must be at least 12 characters] |\n\n## UI/UX Considerations\n\nNotes on how this feature should present to the user. Reference UX requirements where applicable.\n\n## Data Requirements\n\nWhat data is created, read, updated, or deleted by this feature. Reference DR documents where applicable.\n\n## Traceability\n\n- **Implements:** [BR-NNN](../business/BR-NNN-slug.md)\n- **Constrained by:** [NFR-NNN](../non-functional/NFR-NNN-slug.md)\n- **Related:** [INT-NNN](../integration/INT-NNN-slug.md)\n- **Depends on (cross-tier):** [XX-NNN](../category/XX-NNN-slug.md) — [platform/industry requirement this depends on]\n- **Enables (cross-tier):** [XX-NNN](../category/XX-NNN-slug.md) — [customer-workflow/consumer-app requirement this enables]\n\n## Open Items\n\n### Identified Gaps\n\n[Document any missing functionality, unhandled edge cases, or incomplete aspects. Number each item and assign a priority (P0/P1/P2/P3). Call out interdependencies with other open items. If none, write \"None identified.\"]\n\n1. **[Gap title]** \\`[P0-P3]\\`\n [Description of what's missing and why it matters.]\n → [Depends on / Blocks]: [XX-NNN Open Item #N](../category/XX-NNN-slug.md#open-items) (if applicable)\n\n### Follow-up Questions\n\n[Document anything ambiguous or where the motivation/reasoning cannot be confidently inferred. Number each item and assign a priority. If none, write \"None identified.\"]\n\n1. **[Question title]** \\`[P0-P3]\\`\n [The question, with context on why the answer matters.]\n → [Depends on / Blocks]: [XX-NNN Open Item #N](../category/XX-NNN-slug.md#open-items) (if applicable)\n\n### Contradictions & Inconsistencies\n\n[Document any conflicts with other requirements, code behavior, or documentation. Number each item and assign a priority. If none, write \"None identified.\"]\n\n1. **[Contradiction title]** \\`[P0-P3]\\`\n [Description of the conflict and what needs to be resolved.]\n → [Depends on / Blocks]: [XX-NNN Open Item #N](../category/XX-NNN-slug.md#open-items) (if applicable)\n\n## Revision History\n\n| Date | Author | Change |\n|---|---|---|\n| YYYY-MM-DD | [Name] | Initial draft |\n`;\n\n/** Verbatim NFR (Non-Functional Requirement) template. */\nconst TEMPLATE_NFR = `---\ntitle: \"NFR-NNN: [Non-Functional Requirement Title]\"\n---\n\n# NFR-NNN: [Non-Functional Requirement Title]\n\n## Metadata\n\n| Field | Value |\n|---|---|\n| **ID** | NFR-NNN |\n| **Status** | Draft |\n| **Tier** | [Platform · Industry · Customer Workflow · Consumer Application] |\n| **Implementor** | [Consortium Member · Customer · TBD — required for Customer Workflow and Consumer Application tiers. When Consortium Member, link to org profile] |\n| **Customer** | [Link to customer org profile if this requirement originated from or applies to a specific customer. Optional for Platform/Industry tiers, expected for Customer Workflow/Consumer Application tiers] |\n| **Quality Attribute** | [Performance / Reliability / Scalability / Maintainability / Portability / Availability] |\n| **Priority** | [Critical / High / Medium / Low] |\n| **Owner** | [Name or role] |\n| **Created** | YYYY-MM-DD |\n| **Last Updated** | YYYY-MM-DD |\n\n## Description\n\nWhat quality attribute this requirement addresses and why it matters for the system.\n\n## Measurable Targets\n\nNon-functional requirements must have numeric, measurable targets — vague statements like \"the system should be fast\" are not acceptable.\n\n| Metric | Target | Measurement Method | Measurement Frequency |\n|---|---|---|---|\n| [e.g., API response time (p99)] | [e.g., < 200ms] | [e.g., Datadog APM percentile tracking] | [e.g., Continuous] |\n| [e.g., System availability] | [e.g., 99.9% monthly] | [e.g., Uptime monitoring (Pingdom/UptimeRobot)] | [e.g., Monthly] |\n\n## Current Baseline\n\nIf this is being applied to an existing system, document the current measured values so improvement can be tracked.\n\n| Metric | Current Value | Date Measured |\n|---|---|---|\n| [Metric] | [Current value or \"Not yet measured\"] | [Date] |\n\n## Rationale\n\nWhy this target was chosen. What business need or user expectation drives this number? What are the consequences of not meeting it?\n\n## Applicable Scope\n\nWhich parts of the system does this requirement apply to? Be specific — \"all API endpoints\" or \"the checkout flow\" rather than \"the system.\"\n\n## Approach\n\nHigh-level approach for meeting this target. Reference ADRs and TRs for implementation details.\n\n## Monitoring & Alerting\n\nHow compliance with this requirement will be monitored in production. Reference OPS requirements where applicable.\n\n| Alert Condition | Threshold | Action |\n|---|---|---|\n| [e.g., p99 latency exceeds target] | [e.g., > 200ms for 5 minutes] | [e.g., Page on-call engineer] |\n\n## Traceability\n\n- **Supports:** [BR-NNN](../business/BR-NNN-slug.md)\n- **Constrains:** [FR-NNN](../functional/FR-NNN-slug.md)\n- **Monitored by:** [OPS-NNN](../operational/OPS-NNN-slug.md)\n- **Depends on (cross-tier):** [XX-NNN](../category/XX-NNN-slug.md) — [platform/industry requirement this depends on]\n- **Enables (cross-tier):** [XX-NNN](../category/XX-NNN-slug.md) — [customer-workflow/consumer-app requirement this enables]\n\n## Open Items\n\n### Identified Gaps\n\n[Document any missing functionality, unhandled edge cases, or incomplete aspects. Number each item and assign a priority (P0/P1/P2/P3). Call out interdependencies with other open items. If none, write \"None identified.\"]\n\n1. **[Gap title]** \\`[P0-P3]\\`\n [Description of what's missing and why it matters.]\n → [Depends on / Blocks]: [XX-NNN Open Item #N](../category/XX-NNN-slug.md#open-items) (if applicable)\n\n### Follow-up Questions\n\n[Document anything ambiguous or where the motivation/reasoning cannot be confidently inferred. Number each item and assign a priority. If none, write \"None identified.\"]\n\n1. **[Question title]** \\`[P0-P3]\\`\n [The question, with context on why the answer matters.]\n → [Depends on / Blocks]: [XX-NNN Open Item #N](../category/XX-NNN-slug.md#open-items) (if applicable)\n\n### Contradictions & Inconsistencies\n\n[Document any conflicts with other requirements, code behavior, or documentation. Number each item and assign a priority. If none, write \"None identified.\"]\n\n1. **[Contradiction title]** \\`[P0-P3]\\`\n [Description of the conflict and what needs to be resolved.]\n → [Depends on / Blocks]: [XX-NNN Open Item #N](../category/XX-NNN-slug.md#open-items) (if applicable)\n\n## Revision History\n\n| Date | Author | Change |\n|---|---|---|\n| YYYY-MM-DD | [Name] | Initial draft |\n`;\n\n/** Verbatim TR (Technical Requirement) template. */\nconst TEMPLATE_TR = `---\ntitle: \"TR-NNN: [Technical Requirement Title]\"\n---\n\n# TR-NNN: [Technical Requirement Title]\n\n## Metadata\n\n| Field | Value |\n|---|---|\n| **ID** | TR-NNN |\n| **Status** | Draft |\n| **Tier** | [Platform · Industry · Customer Workflow · Consumer Application] |\n| **Implementor** | [Consortium Member · Customer · TBD — required for Customer Workflow and Consumer Application tiers. When Consortium Member, link to org profile] |\n| **Customer** | [Link to customer org profile if this requirement originated from or applies to a specific customer. Optional for Platform/Industry tiers, expected for Customer Workflow/Consumer Application tiers] |\n| **Category** | [Language / Framework / Database / Infrastructure / Library / Tool] |\n| **Owner** | [Name or role] |\n| **Created** | YYYY-MM-DD |\n| **Last Updated** | YYYY-MM-DD |\n\n## Technology Choice\n\nWhen **Accepted**: Fill in the selected technology.\n\nWhen **Proposed**: Write \"Pending human review. See Recommendation below.\" and leave Version/License/Vendor as TBD.\n\n| Field | Value |\n|---|---|\n| **Technology** | [e.g., PostgreSQL] |\n| **Version** | [e.g., 16+ (observed: 16-alpine at time of documentation). Version will naturally drift upward through routine maintenance.] |\n| **License** | [e.g., PostgreSQL License (permissive, OSI-approved)] |\n| **Vendor/Maintainer** | [e.g., PostgreSQL Global Development Group] |\n\n## Alternatives Considered\n\nList every viable technology option, including the recommended one. Each alternative gets the same level of analysis.\n\n### Option 1: [Technology Name]\n\n**Description:** [What this technology is and how it would be used]\n\n**Pros:**\n- [Pro 1]\n- [Pro 2]\n\n**Cons:**\n- [Con 1]\n- [Con 2]\n\n**License:** [License type]\n**Maturity:** [Established / Growing / Emerging]\n\n### Option 2: [Technology Name]\n\n**Description:** [What this technology is and how it would be used]\n\n**Pros:**\n- [Pro 1]\n\n**Cons:**\n- [Con 1]\n\n**License:** [License type]\n**Maturity:** [Established / Growing / Emerging]\n\n## Recommendation\n\n**Recommended option:** [Name of the recommended technology]\n\n**Why this option:** [A well-reasoned explanation of why this technology best fits the context, constraints, and goals. Address the key trade-offs honestly — explain why the cons are acceptable and why other options were not preferred.]\n\n**Key trade-offs accepted:** [What you're giving up by choosing this option over others]\n\nWhen the status is \\`Proposed\\`, this section frames the decision for the human reviewer. When \\`Accepted\\`, this section documents the reasoning behind the choice.\n\n## Rationale\n\nWhen **Accepted**: Summarize why this technology was selected. Reference the ADR that records the decision process if one exists.\n\nWhen **Proposed**: Write \"See Recommendation above. Awaiting human decision.\"\n\n## Usage Context\n\nHow and where this technology is used in the system. Be specific about which components or layers depend on it.\n\n## Version Constraints\n\nAny version pinning, upgrade policies, or compatibility requirements. Assume versions will drift upward over time through routine maintenance unless there is a specific reason to pin.\n\n- **Minimum version:** [version — the floor below which compatibility is not guaranteed]\n- **Observed version:** [version at time of documentation]\n- **Maximum version:** [version or \"latest stable\" — only specify if there's a known ceiling]\n- **Upgrade policy:** [e.g., \"Track latest minor releases within 30 days; major version upgrades require ADR\"]\n- **Version-sensitive notes:** [Any specific features or APIs used that depend on this version floor — helps future developers understand what might break if they don't meet the minimum]\n\n## Configuration Standards\n\nKey configuration decisions, defaults, or standards that apply to this technology across the project.\n\n## Dependencies & Compatibility\n\nOther technologies this choice interacts with, and any known compatibility constraints.\n\n| Dependency | Relationship | Constraint |\n|---|---|---|\n| [e.g., Node.js runtime] | [Required by] | [e.g., v18 LTS or later] |\n\n## Risks & Mitigations\n\n| Risk | Likelihood | Impact | Mitigation |\n|---|---|---|---|\n| [e.g., Vendor discontinues support] | [Low/Medium/High] | [Low/Medium/High] | [e.g., Open-source, community-maintained] |\n\n## Traceability\n\n- **Justified by:** [ADR-NNN](../architectural-decisions/ADR-NNN-slug.md)\n- **Supports:** [FR-NNN](../functional/FR-NNN-slug.md)\n- **Constrained by:** [NFR-NNN](../non-functional/NFR-NNN-slug.md)\n- **Depends on (cross-tier):** [XX-NNN](../category/XX-NNN-slug.md) — [platform/industry requirement this depends on]\n- **Enables (cross-tier):** [XX-NNN](../category/XX-NNN-slug.md) — [customer-workflow/consumer-app requirement this enables]\n\n## Open Items\n\n### Identified Gaps\n\n[Document any missing functionality, unhandled edge cases, or incomplete aspects. Number each item and assign a priority (P0/P1/P2/P3). Call out interdependencies with other open items. If none, write \"None identified.\"]\n\n1. **[Gap title]** \\`[P0-P3]\\`\n [Description of what's missing and why it matters.]\n → [Depends on / Blocks]: [XX-NNN Open Item #N](../category/XX-NNN-slug.md#open-items) (if applicable)\n\n### Follow-up Questions\n\n[Document anything ambiguous or where the motivation/reasoning cannot be confidently inferred. Number each item and assign a priority. If none, write \"None identified.\"]\n\n1. **[Question title]** \\`[P0-P3]\\`\n [The question, with context on why the answer matters.]\n → [Depends on / Blocks]: [XX-NNN Open Item #N](../category/XX-NNN-slug.md#open-items) (if applicable)\n\n### Contradictions & Inconsistencies\n\n[Document any conflicts with other requirements, code behavior, or documentation. Number each item and assign a priority. If none, write \"None identified.\"]\n\n1. **[Contradiction title]** \\`[P0-P3]\\`\n [Description of the conflict and what needs to be resolved.]\n → [Depends on / Blocks]: [XX-NNN Open Item #N](../category/XX-NNN-slug.md#open-items) (if applicable)\n\n## Revision History\n\n| Date | Author | Change |\n|---|---|---|\n| YYYY-MM-DD | [Name] | Initial draft |\n`;\n\n/** Verbatim ADR (Architectural Decision Record) template. */\nconst TEMPLATE_ADR = `---\ntitle: \"ADR-NNN: [Decision Title]\"\n---\n\n# ADR-NNN: [Decision Title]\n\n## Metadata\n\n| Field | Value |\n|---|---|\n| **ID** | ADR-NNN |\n| **Status** | Draft |\n| **Tier** | [Platform · Industry · Customer Workflow · Consumer Application] |\n| **Implementor** | [Consortium Member · Customer · TBD — required for Customer Workflow and Consumer Application tiers. When Consortium Member, link to org profile] |\n| **Customer** | [Link to customer org profile if this requirement originated from or applies to a specific customer. Optional for Platform/Industry tiers, expected for Customer Workflow/Consumer Application tiers] |\n| **Decision Date** | YYYY-MM-DD |\n| **Decision Makers** | [Names or roles involved in the decision] |\n| **Created** | YYYY-MM-DD |\n| **Last Updated** | YYYY-MM-DD |\n\n## Context\n\nWhat is the issue that we're seeing that motivates this decision or change? What forces are at play — technical constraints, business pressures, team capabilities, timeline?\n\n## Decision\n\nWhen **Accepted**: State the architectural decision clearly and concisely. Start with \"We will...\" or \"We have decided to...\"\n\nWhen **Proposed**: Write \"Pending human review. See Recommendation below.\" Do not make the decision — present the analysis so a human can decide.\n\n## Alternatives Considered\n\nList every viable option, including the recommended one. Each alternative gets the same level of analysis — do not shortchange options you don't prefer.\n\n### Alternative 1: [Name]\n\n**Description:** [What this alternative entails — enough detail to evaluate it]\n\n**Pros:**\n- [Pro 1]\n- [Pro 2]\n\n**Cons:**\n- [Con 1]\n- [Con 2]\n\n### Alternative 2: [Name]\n\n**Description:** [What this alternative entails]\n\n**Pros:**\n- [Pro 1]\n\n**Cons:**\n- [Con 1]\n\n## Recommendation\n\n**Recommended option:** [Name of the recommended alternative]\n\n**Why this option:** [A well-reasoned explanation of why this alternative best fits the context, constraints, and goals. Address the key trade-offs honestly — explain why the cons of the recommended option are acceptable and why the pros of rejected alternatives don't outweigh their cons in this context.]\n\n**Key trade-offs accepted:** [What you're giving up by choosing this option over others]\n\nWhen the status is \\`Proposed\\`, this section frames the decision for the human reviewer. When \\`Accepted\\`, this section documents the reasoning behind the choice.\n\n## Consequences\n\n### Positive\n\n- [Positive consequence 1]\n- [Positive consequence 2]\n\n### Negative\n\n- [Negative consequence 1 — every decision has trade-offs; document them honestly]\n- [Negative consequence 2]\n\n### Neutral\n\n- [Neutral observation about what changes as a result of this decision]\n\n## Compliance & Constraints\n\nAny regulatory, security, or organizational constraints that influenced this decision.\n\n## Implementation Notes\n\nHigh-level guidance for implementing this decision. Detailed implementation goes in TR and FR documents.\n\n## Traceability\n\n- **Supports:** [BR-NNN](../business/BR-NNN-slug.md)\n- **Implemented by:** [TR-NNN](../technical/TR-NNN-slug.md)\n- **Related:** [ADR-NNN](ADR-NNN-slug.md)\n- **Depends on (cross-tier):** [XX-NNN](../category/XX-NNN-slug.md) — [platform/industry requirement this depends on]\n- **Enables (cross-tier):** [XX-NNN](../category/XX-NNN-slug.md) — [customer-workflow/consumer-app requirement this enables]\n\n## Open Items\n\n### Identified Gaps\n\n[Document any missing functionality, unhandled edge cases, or incomplete aspects. Number each item and assign a priority (P0/P1/P2/P3). Call out interdependencies with other open items. If none, write \"None identified.\"]\n\n1. **[Gap title]** \\`[P0-P3]\\`\n [Description of what's missing and why it matters.]\n → [Depends on / Blocks]: [XX-NNN Open Item #N](../category/XX-NNN-slug.md#open-items) (if applicable)\n\n### Follow-up Questions\n\n[Document anything ambiguous or where the motivation/reasoning cannot be confidently inferred. Number each item and assign a priority. If none, write \"None identified.\"]\n\n1. **[Question title]** \\`[P0-P3]\\`\n [The question, with context on why the answer matters.]\n → [Depends on / Blocks]: [XX-NNN Open Item #N](../category/XX-NNN-slug.md#open-items) (if applicable)\n\n### Contradictions & Inconsistencies\n\n[Document any conflicts with other requirements, code behavior, or documentation. Number each item and assign a priority. If none, write \"None identified.\"]\n\n1. **[Contradiction title]** \\`[P0-P3]\\`\n [Description of the conflict and what needs to be resolved.]\n → [Depends on / Blocks]: [XX-NNN Open Item #N](../category/XX-NNN-slug.md#open-items) (if applicable)\n\n## Revision History\n\n| Date | Author | Change |\n|---|---|---|\n| YYYY-MM-DD | [Name] | Initial draft |\n`;\n\n/** Verbatim SEC (Security & Compliance) template. */\nconst TEMPLATE_SEC = `---\ntitle: \"SEC-NNN: [Security Requirement Title]\"\n---\n\n# SEC-NNN: [Security Requirement Title]\n\n## Metadata\n\n| Field | Value |\n|---|---|\n| **ID** | SEC-NNN |\n| **Status** | Draft |\n| **Tier** | [Platform · Industry · Customer Workflow · Consumer Application] |\n| **Implementor** | [Consortium Member · Customer · TBD — required for Customer Workflow and Consumer Application tiers. When Consortium Member, link to org profile] |\n| **Customer** | [Link to customer org profile if this requirement originated from or applies to a specific customer. Optional for Platform/Industry tiers, expected for Customer Workflow/Consumer Application tiers] |\n| **Security Domain** | [Authentication / Authorization / Data Protection / Audit / Compliance / Network / Input Validation] |\n| **Priority** | [Critical / High / Medium / Low] |\n| **Owner** | [Name or role] |\n| **Created** | YYYY-MM-DD |\n| **Last Updated** | YYYY-MM-DD |\n\n## Description\n\nWhat security concern this requirement addresses and why it matters.\n\n## Threat Model Reference\n\nWhat threats does this requirement mitigate? Reference any formal threat modeling artifacts if they exist.\n\n| Threat | STRIDE Category | Severity | This Requirement Mitigates |\n|---|---|---|---|\n| [e.g., Unauthorized access to tenant data] | [e.g., Elevation of Privilege] | [Critical/High/Medium/Low] | [How] |\n\n## Requirements\n\n### Controls\n\nSpecific security controls that must be implemented.\n\n| Control ID | Description | OWASP ASVS Ref | NIST 800-53 Ref |\n|---|---|---|---|\n| [e.g., SEC-001-C1] | [e.g., All passwords hashed with bcrypt, cost factor ≥ 12] | [e.g., V2.4.1] | [e.g., IA-5(1)] |\n\n### Policies\n\nOrganizational or procedural security policies this requirement enforces.\n\n- [Policy 1]\n- [Policy 2]\n\n## Applicable Regulations\n\n| Regulation | Requirement | How We Comply |\n|---|---|---|\n| [e.g., SOC 2 Type II] | [e.g., Access controls and audit logging] | [e.g., RBAC + immutable audit log] |\n| [e.g., GDPR] | [e.g., Data encryption at rest] | [e.g., AES-256 via AWS KMS] |\n\n## Validation Approach\n\nHow compliance with this security requirement will be verified.\n\n| Method | Frequency | Responsible Party |\n|---|---|---|\n| [e.g., Automated security scan] | [e.g., Every CI build] | [e.g., DevOps] |\n| [e.g., Penetration test] | [e.g., Annually] | [e.g., External vendor] |\n\n## Acceptance Criteria\n\n- [ ] [Specific, verifiable security condition]\n- [ ] [e.g., No passwords stored in plaintext anywhere in the system]\n- [ ] [e.g., All API endpoints require authentication except explicitly whitelisted public routes]\n\n## Traceability\n\n- **Protects:** [FR-NNN](../functional/FR-NNN-slug.md)\n- **Constrained by:** [NFR-NNN](../non-functional/NFR-NNN-slug.md)\n- **Implements:** [BR-NNN](../business/BR-NNN-slug.md)\n- **Related data:** [DR-NNN](../data/DR-NNN-slug.md)\n- **Depends on (cross-tier):** [XX-NNN](../category/XX-NNN-slug.md) — [platform/industry requirement this depends on]\n- **Enables (cross-tier):** [XX-NNN](../category/XX-NNN-slug.md) — [customer-workflow/consumer-app requirement this enables]\n\n## Open Items\n\n### Identified Gaps\n\n[Document any missing functionality, unhandled edge cases, or incomplete aspects. Number each item and assign a priority (P0/P1/P2/P3). Call out interdependencies with other open items. If none, write \"None identified.\"]\n\n1. **[Gap title]** \\`[P0-P3]\\`\n [Description of what's missing and why it matters.]\n → [Depends on / Blocks]: [XX-NNN Open Item #N](../category/XX-NNN-slug.md#open-items) (if applicable)\n\n### Follow-up Questions\n\n[Document anything ambiguous or where the motivation/reasoning cannot be confidently inferred. Number each item and assign a priority. If none, write \"None identified.\"]\n\n1. **[Question title]** \\`[P0-P3]\\`\n [The question, with context on why the answer matters.]\n → [Depends on / Blocks]: [XX-NNN Open Item #N](../category/XX-NNN-slug.md#open-items) (if applicable)\n\n### Contradictions & Inconsistencies\n\n[Document any conflicts with other requirements, code behavior, or documentation. Number each item and assign a priority. If none, write \"None identified.\"]\n\n1. **[Contradiction title]** \\`[P0-P3]\\`\n [Description of the conflict and what needs to be resolved.]\n → [Depends on / Blocks]: [XX-NNN Open Item #N](../category/XX-NNN-slug.md#open-items) (if applicable)\n\n## Revision History\n\n| Date | Author | Change |\n|---|---|---|\n| YYYY-MM-DD | [Name] | Initial draft |\n`;\n\n/** Verbatim DR (Data Requirement) template. */\nconst TEMPLATE_DR = `---\ntitle: \"DR-NNN: [Data Requirement Title]\"\n---\n\n# DR-NNN: [Data Requirement Title]\n\n## Metadata\n\n| Field | Value |\n|---|---|\n| **ID** | DR-NNN |\n| **Status** | Draft |\n| **Tier** | [Platform · Industry · Customer Workflow · Consumer Application] |\n| **Implementor** | [Consortium Member · Customer · TBD — required for Customer Workflow and Consumer Application tiers. When Consortium Member, link to org profile] |\n| **Customer** | [Link to customer org profile if this requirement originated from or applies to a specific customer. Optional for Platform/Industry tiers, expected for Customer Workflow/Consumer Application tiers] |\n| **Data Domain** | [e.g., User Data / Transaction Data / Configuration / Audit Logs / Media Assets] |\n| **Classification** | [Public / Internal / Confidential / Restricted] |\n| **Owner** | [Name or role] |\n| **Created** | YYYY-MM-DD |\n| **Last Updated** | YYYY-MM-DD |\n\n## Description\n\nWhat data this requirement governs, why it exists, and its significance to the system.\n\n## Data Model\n\nDescribe the key entities, their attributes, and relationships. Include an entity-relationship summary or reference a diagram.\n\n| Entity | Key Attributes | Relationships |\n|---|---|---|\n| [e.g., User] | [e.g., id, email, name, created_at] | [e.g., Has many Organizations (via membership)] |\n\n## Data Lifecycle\n\n| Phase | Description | Duration |\n|---|---|---|\n| Creation | [How and when this data is created] | — |\n| Active Use | [How this data is used during normal operations] | [e.g., Indefinite while account active] |\n| Archival | [If/how data is archived after active use] | [e.g., After 12 months of inactivity] |\n| Deletion | [When and how data is permanently removed] | [e.g., 90 days after account closure] |\n\n## Retention Policy\n\n| Data Type | Retention Period | Legal Basis | Deletion Method |\n|---|---|---|---|\n| [e.g., User profile data] | [e.g., Account lifetime + 90 days] | [e.g., Contractual obligation] | [e.g., Soft delete → hard delete after retention] |\n| [e.g., Audit logs] | [e.g., 7 years] | [e.g., SOC 2 compliance] | [e.g., Automated purge] |\n\n## Backup & Recovery\n\n| Parameter | Value |\n|---|---|\n| **RPO (Recovery Point Objective)** | [e.g., < 1 hour — maximum acceptable data loss] |\n| **RTO (Recovery Time Objective)** | [e.g., < 4 hours — maximum acceptable downtime] |\n| **Backup Frequency** | [e.g., Continuous WAL archiving + daily snapshots] |\n| **Backup Location** | [e.g., Cross-region S3 with encryption] |\n| **Recovery Testing** | [e.g., Quarterly restore test] |\n\n## Data Quality Rules\n\n| Rule | Description | Enforcement |\n|---|---|---|\n| [e.g., Email uniqueness] | [e.g., No two active users may share an email] | [e.g., Database unique constraint] |\n\n## Privacy & Classification\n\nHow this data is classified and what handling rules apply based on that classification.\n\n| Classification Level | Handling Rules |\n|---|---|\n| Public | No restrictions |\n| Internal | Access controlled, not shared externally |\n| Confidential | Encrypted at rest, access logged, need-to-know basis |\n| Restricted | All of Confidential + additional controls per regulation |\n\n## Traceability\n\n- **Supports:** [FR-NNN](../functional/FR-NNN-slug.md)\n- **Protected by:** [SEC-NNN](../security/SEC-NNN-slug.md)\n- **Stored per:** [TR-NNN](../technical/TR-NNN-slug.md)\n- **Depends on (cross-tier):** [XX-NNN](../category/XX-NNN-slug.md) — [platform/industry requirement this depends on]\n- **Enables (cross-tier):** [XX-NNN](../category/XX-NNN-slug.md) — [customer-workflow/consumer-app requirement this enables]\n\n## Open Items\n\n### Identified Gaps\n\n[Document any missing functionality, unhandled edge cases, or incomplete aspects. Number each item and assign a priority (P0/P1/P2/P3). Call out interdependencies with other open items. If none, write \"None identified.\"]\n\n1. **[Gap title]** \\`[P0-P3]\\`\n [Description of what's missing and why it matters.]\n → [Depends on / Blocks]: [XX-NNN Open Item #N](../category/XX-NNN-slug.md#open-items) (if applicable)\n\n### Follow-up Questions\n\n[Document anything ambiguous or where the motivation/reasoning cannot be confidently inferred. Number each item and assign a priority. If none, write \"None identified.\"]\n\n1. **[Question title]** \\`[P0-P3]\\`\n [The question, with context on why the answer matters.]\n → [Depends on / Blocks]: [XX-NNN Open Item #N](../category/XX-NNN-slug.md#open-items) (if applicable)\n\n### Contradictions & Inconsistencies\n\n[Document any conflicts with other requirements, code behavior, or documentation. Number each item and assign a priority. If none, write \"None identified.\"]\n\n1. **[Contradiction title]** \\`[P0-P3]\\`\n [Description of the conflict and what needs to be resolved.]\n → [Depends on / Blocks]: [XX-NNN Open Item #N](../category/XX-NNN-slug.md#open-items) (if applicable)\n\n## Revision History\n\n| Date | Author | Change |\n|---|---|---|\n| YYYY-MM-DD | [Name] | Initial draft |\n`;\n\n/** Verbatim INT (Integration Requirement) template. */\nconst TEMPLATE_INT = `---\ntitle: \"INT-NNN: [Integration Requirement Title]\"\n---\n\n# INT-NNN: [Integration Requirement Title]\n\n## Metadata\n\n| Field | Value |\n|---|---|\n| **ID** | INT-NNN |\n| **Status** | Draft |\n| **Tier** | [Platform · Industry · Customer Workflow · Consumer Application] |\n| **Implementor** | [Consortium Member · Customer · TBD — required for Customer Workflow and Consumer Application tiers. When Consortium Member, link to org profile] |\n| **Customer** | [Link to customer org profile if this requirement originated from or applies to a specific customer. Optional for Platform/Industry tiers, expected for Customer Workflow/Consumer Application tiers] |\n| **Integration Type** | [REST API / GraphQL / Webhook / Message Queue / File Transfer / SDK] |\n| **Direction** | [Inbound / Outbound / Bidirectional] |\n| **External System** | [Name of the third-party or internal system] |\n| **Owner** | [Name or role] |\n| **Created** | YYYY-MM-DD |\n| **Last Updated** | YYYY-MM-DD |\n\n## Description\n\nWhat this integration does, why it's needed, and what business capability it enables.\n\n## External System Overview\n\n| Field | Value |\n|---|---|\n| **System** | [e.g., Stripe] |\n| **Purpose** | [e.g., Payment processing and subscription management] |\n| **API Documentation** | [URL to official docs] |\n| **API Version** | [e.g., 2023-10-16] |\n| **Authentication** | [e.g., API key (secret key in header)] |\n\n## Integration Points\n\n### [Endpoint/Event 1]: [Name]\n\n| Field | Value |\n|---|---|\n| **Direction** | [Inbound/Outbound] |\n| **Protocol** | [e.g., HTTPS REST] |\n| **Endpoint** | [e.g., POST /v1/customers] |\n| **Authentication** | [e.g., Bearer token] |\n| **Rate Limit** | [e.g., 100 requests/second] |\n\n**Request/Payload:**\n\\`\\`\\`\n[Brief description or schema reference]\n\\`\\`\\`\n\n**Response/Output:**\n\\`\\`\\`\n[Brief description or schema reference]\n\\`\\`\\`\n\n## Error Handling\n\n| Error Scenario | Strategy | Retry Policy |\n|---|---|---|\n| [e.g., 429 Rate Limited] | [e.g., Exponential backoff] | [e.g., 3 retries, max 30s] |\n| [e.g., 500 Server Error] | [e.g., Retry with circuit breaker] | [e.g., 3 retries, then circuit open for 60s] |\n| [e.g., Timeout] | [e.g., Retry once, then dead letter queue] | [e.g., 30s timeout, 1 retry] |\n\n## Data Mapping\n\nHow data maps between our system and the external system.\n\n| Our Field | External Field | Transformation |\n|---|---|---|\n| [e.g., user.email] | [e.g., customer.email] | [e.g., Direct mapping] |\n\n## SLA & Availability\n\n| Parameter | Our Expectation | External System's Published SLA |\n|---|---|---|\n| Availability | [e.g., 99.9%] | [e.g., 99.99%] |\n| Response Time | [e.g., < 500ms p99] | [e.g., < 200ms typical] |\n\n## Fallback Behavior\n\nWhat happens when this integration is unavailable. How does the system degrade gracefully?\n\n## Testing Strategy\n\n| Environment | Approach |\n|---|---|\n| Development | [e.g., Mock server / sandbox environment] |\n| Staging | [e.g., Sandbox API with test credentials] |\n| Production | [e.g., Live API with monitoring] |\n\n## Traceability\n\n- **Enables:** [FR-NNN](../functional/FR-NNN-slug.md)\n- **Constrained by:** [NFR-NNN](../non-functional/NFR-NNN-slug.md)\n- **Secured by:** [SEC-NNN](../security/SEC-NNN-slug.md)\n- **Depends on (cross-tier):** [XX-NNN](../category/XX-NNN-slug.md) — [platform/industry requirement this depends on]\n- **Enables (cross-tier):** [XX-NNN](../category/XX-NNN-slug.md) — [customer-workflow/consumer-app requirement this enables]\n\n## Open Items\n\n### Identified Gaps\n\n[Document any missing functionality, unhandled edge cases, or incomplete aspects. Number each item and assign a priority (P0/P1/P2/P3). Call out interdependencies with other open items. If none, write \"None identified.\"]\n\n1. **[Gap title]** \\`[P0-P3]\\`\n [Description of what's missing and why it matters.]\n → [Depends on / Blocks]: [XX-NNN Open Item #N](../category/XX-NNN-slug.md#open-items) (if applicable)\n\n### Follow-up Questions\n\n[Document anything ambiguous or where the motivation/reasoning cannot be confidently inferred. Number each item and assign a priority. If none, write \"None identified.\"]\n\n1. **[Question title]** \\`[P0-P3]\\`\n [The question, with context on why the answer matters.]\n → [Depends on / Blocks]: [XX-NNN Open Item #N](../category/XX-NNN-slug.md#open-items) (if applicable)\n\n### Contradictions & Inconsistencies\n\n[Document any conflicts with other requirements, code behavior, or documentation. Number each item and assign a priority. If none, write \"None identified.\"]\n\n1. **[Contradiction title]** \\`[P0-P3]\\`\n [Description of the conflict and what needs to be resolved.]\n → [Depends on / Blocks]: [XX-NNN Open Item #N](../category/XX-NNN-slug.md#open-items) (if applicable)\n\n## Revision History\n\n| Date | Author | Change |\n|---|---|---|\n| YYYY-MM-DD | [Name] | Initial draft |\n`;\n\n/** Verbatim OPS (Operational Requirement) template. */\nconst TEMPLATE_OPS = `---\ntitle: \"OPS-NNN: [Operational Requirement Title]\"\n---\n\n# OPS-NNN: [Operational Requirement Title]\n\n## Metadata\n\n| Field | Value |\n|---|---|\n| **ID** | OPS-NNN |\n| **Status** | Draft |\n| **Tier** | [Platform · Industry · Customer Workflow · Consumer Application] |\n| **Implementor** | [Consortium Member · Customer · TBD — required for Customer Workflow and Consumer Application tiers. When Consortium Member, link to org profile] |\n| **Customer** | [Link to customer org profile if this requirement originated from or applies to a specific customer. Optional for Platform/Industry tiers, expected for Customer Workflow/Consumer Application tiers] |\n| **Operations Domain** | [Deployment / Monitoring / Alerting / Logging / Incident Response / Backup] |\n| **Owner** | [Name or role] |\n| **Created** | YYYY-MM-DD |\n| **Last Updated** | YYYY-MM-DD |\n\n## Description\n\nWhat operational concern this requirement addresses and why it matters for system reliability.\n\n## Current State\n\nIf this applies to an existing system, document the current operational posture.\n\n## Requirements\n\n### Deployment\n\n| Parameter | Requirement |\n|---|---|\n| **Strategy** | [e.g., Blue-green / Rolling / Canary] |\n| **Frequency** | [e.g., On-demand, multiple times per day] |\n| **Rollback** | [e.g., Automated rollback on health check failure within 5 minutes] |\n| **Downtime** | [e.g., Zero-downtime required] |\n\n### Monitoring & Observability\n\n| Signal Type | What to Monitor | Tool | Retention |\n|---|---|---|---|\n| **Metrics** | [e.g., Request rate, error rate, latency p50/p95/p99] | [e.g., Datadog] | [e.g., 15 months] |\n| **Logs** | [e.g., Application logs, access logs, audit logs] | [e.g., CloudWatch → S3] | [e.g., 90 days hot, 1 year cold] |\n| **Traces** | [e.g., Distributed request traces] | [e.g., Datadog APM] | [e.g., 30 days] |\n\n### Alerting\n\n| Alert | Condition | Severity | Notification Channel | Escalation |\n|---|---|---|---|---|\n| [e.g., High error rate] | [e.g., 5xx rate > 1% for 5 min] | [e.g., P1 / Critical] | [e.g., PagerDuty → on-call] | [e.g., If unack'd in 15 min → engineering lead] |\n\n### Incident Response\n\n| Severity | Response Time | Resolution Target | Communication |\n|---|---|---|---|\n| P1 (Critical) | [e.g., 15 minutes] | [e.g., 1 hour] | [e.g., Status page + stakeholder notification] |\n| P2 (Major) | [e.g., 30 minutes] | [e.g., 4 hours] | [e.g., Status page if customer-facing] |\n| P3 (Minor) | [e.g., Next business day] | [e.g., 5 business days] | [e.g., Internal tracking only] |\n\n## Runbook References\n\n| Scenario | Runbook Location |\n|---|---|\n| [e.g., Database failover] | [Link or path] |\n| [e.g., High memory usage] | [Link or path] |\n\n## Environments\n\n| Environment | Purpose | Infrastructure | Access |\n|---|---|---|---|\n| Development | [Local development] | [e.g., Docker Compose] | [e.g., All developers] |\n| Staging | [Pre-production testing] | [e.g., AWS, scaled down] | [e.g., Engineering team] |\n| Production | [Live system] | [e.g., AWS, full scale] | [e.g., Restricted, via bastion] |\n\n## Traceability\n\n- **Monitors:** [NFR-NNN](../non-functional/NFR-NNN-slug.md)\n- **Supports:** [BR-NNN](../business/BR-NNN-slug.md)\n- **Uses:** [TR-NNN](../technical/TR-NNN-slug.md)\n- **Depends on (cross-tier):** [XX-NNN](../category/XX-NNN-slug.md) — [platform/industry requirement this depends on]\n- **Enables (cross-tier):** [XX-NNN](../category/XX-NNN-slug.md) — [customer-workflow/consumer-app requirement this enables]\n\n## Open Items\n\n### Identified Gaps\n\n[Document any missing functionality, unhandled edge cases, or incomplete aspects. Number each item and assign a priority (P0/P1/P2/P3). Call out interdependencies with other open items. If none, write \"None identified.\"]\n\n1. **[Gap title]** \\`[P0-P3]\\`\n [Description of what's missing and why it matters.]\n → [Depends on / Blocks]: [XX-NNN Open Item #N](../category/XX-NNN-slug.md#open-items) (if applicable)\n\n### Follow-up Questions\n\n[Document anything ambiguous or where the motivation/reasoning cannot be confidently inferred. Number each item and assign a priority. If none, write \"None identified.\"]\n\n1. **[Question title]** \\`[P0-P3]\\`\n [The question, with context on why the answer matters.]\n → [Depends on / Blocks]: [XX-NNN Open Item #N](../category/XX-NNN-slug.md#open-items) (if applicable)\n\n### Contradictions & Inconsistencies\n\n[Document any conflicts with other requirements, code behavior, or documentation. Number each item and assign a priority. If none, write \"None identified.\"]\n\n1. **[Contradiction title]** \\`[P0-P3]\\`\n [Description of the conflict and what needs to be resolved.]\n → [Depends on / Blocks]: [XX-NNN Open Item #N](../category/XX-NNN-slug.md#open-items) (if applicable)\n\n## Revision History\n\n| Date | Author | Change |\n|---|---|---|\n| YYYY-MM-DD | [Name] | Initial draft |\n`;\n\n/** Verbatim UX (UX Requirement) template. */\nconst TEMPLATE_UX = `---\ntitle: \"UX-NNN: [UX Requirement Title]\"\n---\n\n# UX-NNN: [UX Requirement Title]\n\n## Metadata\n\n| Field | Value |\n|---|---|\n| **ID** | UX-NNN |\n| **Status** | Draft |\n| **Tier** | [Platform · Industry · Customer Workflow · Consumer Application] |\n| **Implementor** | [Consortium Member · Customer · TBD — required for Customer Workflow and Consumer Application tiers. When Consortium Member, link to org profile] |\n| **Customer** | [Link to customer org profile if this requirement originated from or applies to a specific customer. Optional for Platform/Industry tiers, expected for Customer Workflow/Consumer Application tiers] |\n| **UX Domain** | [Accessibility / Responsiveness / Internationalization / Interaction Design / Information Architecture] |\n| **Priority** | [Critical / High / Medium / Low] |\n| **Owner** | [Name or role] |\n| **Created** | YYYY-MM-DD |\n| **Last Updated** | YYYY-MM-DD |\n\n## Description\n\nWhat user experience concern this requirement addresses and why it matters.\n\n## Target Users\n\n| User Segment | Characteristics | Key Needs |\n|---|---|---|\n| [e.g., Power users] | [e.g., Daily usage, keyboard-heavy workflow] | [e.g., Keyboard shortcuts, bulk actions] |\n\n## Accessibility\n\n| Parameter | Requirement |\n|---|---|\n| **WCAG Level** | [e.g., 2.1 Level AA] |\n| **Screen Reader Support** | [e.g., ARIA labels on all interactive elements] |\n| **Keyboard Navigation** | [e.g., All functionality accessible via keyboard] |\n| **Color Contrast** | [e.g., Minimum 4.5:1 for normal text, 3:1 for large text] |\n| **Motion** | [e.g., Respect prefers-reduced-motion; no auto-playing animations] |\n\n## Responsive Design\n\n| Breakpoint | Target Devices | Layout Behavior |\n|---|---|---|\n| [e.g., < 375px] | [e.g., Small phones] | [e.g., Single column, stacked navigation] |\n| [e.g., 375–768px] | [e.g., Phones, small tablets] | [e.g., Single column, hamburger menu] |\n| [e.g., 768–1024px] | [e.g., Tablets] | [e.g., Two-column where appropriate] |\n| [e.g., > 1024px] | [e.g., Desktop] | [e.g., Full layout with sidebar navigation] |\n\n## Internationalization (i18n)\n\n| Parameter | Requirement |\n|---|---|\n| **Supported Languages** | [e.g., English (launch), Spanish, French (Phase 2)] |\n| **Text Direction** | [e.g., LTR only at launch; RTL support in backlog] |\n| **Date/Time Formats** | [e.g., Locale-aware formatting] |\n| **Currency** | [e.g., Display in user's locale, store in USD] |\n\n## Interaction Patterns\n\nKey interaction patterns and principles that apply to this requirement.\n\n| Pattern | Standard | Notes |\n|---|---|---|\n| [e.g., Form validation] | [e.g., Inline validation on blur, summary on submit] | [e.g., Error messages adjacent to field] |\n| [e.g., Loading states] | [e.g., Skeleton screens for content, spinners for actions] | [e.g., No blank screens during loads] |\n\n## Design System Reference\n\nReference to the project's design system, component library, or style guide if one exists.\n\n## Acceptance Criteria\n\n- [ ] [Specific, verifiable UX condition]\n- [ ] [e.g., All pages score ≥ 90 on Lighthouse accessibility audit]\n- [ ] [e.g., All interactive elements have visible focus indicators]\n\n## Traceability\n\n- **Enhances:** [FR-NNN](../functional/FR-NNN-slug.md)\n- **Constrained by:** [NFR-NNN](../non-functional/NFR-NNN-slug.md)\n- **Supports:** [BR-NNN](../business/BR-NNN-slug.md)\n- **Depends on (cross-tier):** [XX-NNN](../category/XX-NNN-slug.md) — [platform/industry requirement this depends on]\n- **Enables (cross-tier):** [XX-NNN](../category/XX-NNN-slug.md) — [customer-workflow/consumer-app requirement this enables]\n\n## Open Items\n\n### Identified Gaps\n\n[Document any missing functionality, unhandled edge cases, or incomplete aspects. Number each item and assign a priority (P0/P1/P2/P3). Call out interdependencies with other open items. If none, write \"None identified.\"]\n\n1. **[Gap title]** \\`[P0-P3]\\`\n [Description of what's missing and why it matters.]\n → [Depends on / Blocks]: [XX-NNN Open Item #N](../category/XX-NNN-slug.md#open-items) (if applicable)\n\n### Follow-up Questions\n\n[Document anything ambiguous or where the motivation/reasoning cannot be confidently inferred. Number each item and assign a priority. If none, write \"None identified.\"]\n\n1. **[Question title]** \\`[P0-P3]\\`\n [The question, with context on why the answer matters.]\n → [Depends on / Blocks]: [XX-NNN Open Item #N](../category/XX-NNN-slug.md#open-items) (if applicable)\n\n### Contradictions & Inconsistencies\n\n[Document any conflicts with other requirements, code behavior, or documentation. Number each item and assign a priority. If none, write \"None identified.\"]\n\n1. **[Contradiction title]** \\`[P0-P3]\\`\n [Description of the conflict and what needs to be resolved.]\n → [Depends on / Blocks]: [XX-NNN Open Item #N](../category/XX-NNN-slug.md#open-items) (if applicable)\n\n## Revision History\n\n| Date | Author | Change |\n|---|---|---|\n| YYYY-MM-DD | [Name] | Initial draft |\n`;\n\n/** Verbatim MT (Multi-Tenancy & Licensing) template. */\nconst TEMPLATE_MT = `---\ntitle: \"MT-NNN: [Multi-Tenancy Requirement Title]\"\n---\n\n# MT-NNN: [Multi-Tenancy Requirement Title]\n\n## Metadata\n\n| Field | Value |\n|---|---|\n| **ID** | MT-NNN |\n| **Status** | Draft |\n| **Tier** | [Platform · Industry · Customer Workflow · Consumer Application] |\n| **Implementor** | [Consortium Member · Customer · TBD — required for Customer Workflow and Consumer Application tiers. When Consortium Member, link to org profile] |\n| **Customer** | [Link to customer org profile if this requirement originated from or applies to a specific customer. Optional for Platform/Industry tiers, expected for Customer Workflow/Consumer Application tiers] |\n| **MT Domain** | [Tenant Isolation / Feature Gating / Usage Metering / Billing / Provisioning / Licensing] |\n| **Priority** | [Critical / High / Medium / Low] |\n| **Owner** | [Name or role] |\n| **Created** | YYYY-MM-DD |\n| **Last Updated** | YYYY-MM-DD |\n\n## Description\n\nWhat multi-tenancy concern this requirement addresses and why it matters for the SaaS product.\n\n## Tenant Isolation Model\n\n| Layer | Isolation Strategy | Details |\n|---|---|---|\n| **Database** | [e.g., Row-level / Schema-per-tenant / Database-per-tenant] | [e.g., tenant_id column on all tenant-scoped tables, enforced by RLS] |\n| **Application** | [e.g., Shared application, tenant context from auth token] | [e.g., Middleware extracts tenant from JWT, injects into query context] |\n| **Infrastructure** | [e.g., Shared infrastructure / Dedicated compute per tenant] | [e.g., Shared at launch, dedicated option for enterprise tier] |\n| **Storage** | [e.g., Shared bucket with tenant prefix / Separate buckets] | [e.g., S3 bucket with tenant-id/ prefix, IAM policies per tenant] |\n\n## Feature Gating\n\n| Feature | Free Tier | Pro Tier | Enterprise Tier |\n|---|---|---|---|\n| [e.g., Number of users] | [e.g., Up to 5] | [e.g., Up to 50] | [e.g., Unlimited] |\n| [e.g., API access] | [e.g., No] | [e.g., Yes, 1000 calls/day] | [e.g., Yes, unlimited] |\n\n### Gating Mechanism\n\nHow feature gates are implemented and managed (e.g., feature flag service, plan-based checks, entitlement system).\n\n## Usage Metering\n\n| Dimension | Unit | Collection Method | Billing Cycle |\n|---|---|---|---|\n| [e.g., API calls] | [e.g., Per request] | [e.g., API gateway counter] | [e.g., Monthly] |\n| [e.g., Storage] | [e.g., GB-month] | [e.g., Nightly calculation] | [e.g., Monthly] |\n\n## Tenant Provisioning\n\n| Step | Action | Duration | Automated? |\n|---|---|---|---|\n| 1 | [e.g., Create tenant record] | [e.g., < 1s] | [e.g., Yes] |\n| 2 | [e.g., Provision database schema/rows] | [e.g., < 5s] | [e.g., Yes] |\n| 3 | [e.g., Configure DNS/subdomain] | [e.g., < 1 min] | [e.g., Yes] |\n\n## Tenant Offboarding\n\nWhat happens when a tenant leaves — data retention, export, cleanup procedures.\n\n## Noisy Neighbor Prevention\n\nHow the system prevents one tenant from degrading the experience of others.\n\n| Strategy | Implementation |\n|---|---|\n| [e.g., Rate limiting] | [e.g., Per-tenant rate limits at API gateway] |\n| [e.g., Resource quotas] | [e.g., Max storage per tenant per tier] |\n\n## Acceptance Criteria\n\n- [ ] [e.g., Tenant A cannot access Tenant B's data under any circumstances]\n- [ ] [e.g., Feature gate changes take effect within 60 seconds]\n- [ ] [e.g., New tenant provisioning completes in under 30 seconds]\n\n## Traceability\n\n- **Implements:** [BR-NNN](../business/BR-NNN-slug.md)\n- **Secured by:** [SEC-NNN](../security/SEC-NNN-slug.md)\n- **Constrained by:** [NFR-NNN](../non-functional/NFR-NNN-slug.md)\n- **Depends on (cross-tier):** [XX-NNN](../category/XX-NNN-slug.md) — [platform/industry requirement this depends on]\n- **Enables (cross-tier):** [XX-NNN](../category/XX-NNN-slug.md) — [customer-workflow/consumer-app requirement this enables]\n\n## Open Items\n\n### Identified Gaps\n\n[Document any missing functionality, unhandled edge cases, or incomplete aspects. Number each item and assign a priority (P0/P1/P2/P3). Call out interdependencies with other open items. If none, write \"None identified.\"]\n\n1. **[Gap title]** \\`[P0-P3]\\`\n [Description of what's missing and why it matters.]\n → [Depends on / Blocks]: [XX-NNN Open Item #N](../category/XX-NNN-slug.md#open-items) (if applicable)\n\n### Follow-up Questions\n\n[Document anything ambiguous or where the motivation/reasoning cannot be confidently inferred. Number each item and assign a priority. If none, write \"None identified.\"]\n\n1. **[Question title]** \\`[P0-P3]\\`\n [The question, with context on why the answer matters.]\n → [Depends on / Blocks]: [XX-NNN Open Item #N](../category/XX-NNN-slug.md#open-items) (if applicable)\n\n### Contradictions & Inconsistencies\n\n[Document any conflicts with other requirements, code behavior, or documentation. Number each item and assign a priority. If none, write \"None identified.\"]\n\n1. **[Contradiction title]** \\`[P0-P3]\\`\n [Description of the conflict and what needs to be resolved.]\n → [Depends on / Blocks]: [XX-NNN Open Item #N](../category/XX-NNN-slug.md#open-items) (if applicable)\n\n## Revision History\n\n| Date | Author | Change |\n|---|---|---|\n| YYYY-MM-DD | [Name] | Initial draft |\n`;\n\n/** Verbatim category-README template (one per requirement directory). */\nconst TEMPLATE_CATEGORY_README = `# [Category Name] Requirements\n\n## Purpose\n\n[One-paragraph description of what belongs in this category and the question it answers.]\n\n## What Belongs Here\n\n- [Type of requirement 1]\n- [Type of requirement 2]\n- [Type of requirement 3]\n\n## What Does NOT Belong Here\n\n| If your requirement looks like... | It probably belongs in... | Why |\n|---|---|---|\n| [e.g., \"The system must respond in < 200ms\"] | [e.g., NFR (Non-Functional)] | [e.g., That's a quality/performance target, not a feature description] |\n\n## Template\n\nUse [\\`_template-{PREFIX}.md\\`](../templates/_template-{PREFIX}.md) for all new documents in this category.\n\n## Current Documents\n\n| ID | Title | Status | Last Updated |\n|---|---|---|---|\n| [{PREFIX}-001](/{PREFIX}-001-slug.md) | [Title] | [Status] | [Date] |\n\n## Conventions\n\n- File naming: \\`{PREFIX}-NNN-descriptive-slug.md\\`\n- Number sequentially — check the table above for the next available number\n- Every document must include YAML frontmatter with a \\`title\\` field\n- Every document must include a \\`## Traceability\\` section\n`;\n\n/** Verbatim top-level requirements README template. */\nconst TEMPLATE_REQUIREMENTS_README = `---\ntitle: \"[Project Name] — Requirements Documentation\"\n---\n\n# [Project Name] — Requirements Documentation\n\nThis directory contains the structured requirements taxonomy for [Project Name]. It covers the full lifecycle from business intent through operational concerns, providing traceability between strategic goals and implementation work.\n\n## Taxonomy Overview\n\n| Category | Prefix | Directory | Purpose |\n|---|---|---|---|\n| Business Requirements | BR | [\\`business/\\`](business/README.md) | Strategic intent, stakeholders, success metrics |\n| Functional Requirements | FR | [\\`functional/\\`](functional/README.md) | User stories, flows, acceptance criteria |\n| Non-Functional Requirements | NFR | [\\`non-functional/\\`](non-functional/README.md) | Performance, scalability, availability targets |\n| Technical Requirements | TR | [\\`technical/\\`](technical/README.md) | Technology choices, framework decisions |\n| Architectural Decisions | ADR | [\\`architectural-decisions/\\`](architectural-decisions/README.md) | Context, decision, consequences (standard ADR format) |\n| Security & Compliance | SEC | [\\`security/\\`](security/README.md) | Auth, encryption, audit, regulatory |\n| Data Requirements | DR | [\\`data/\\`](data/README.md) | Data models, retention, classification, RPO/RTO |\n| Integration Requirements | INT | [\\`integration/\\`](integration/README.md) | APIs, third-party systems, protocols |\n| Operational Requirements | OPS | [\\`operational/\\`](operational/README.md) | Deployment, monitoring, alerting, logging |\n| UX Requirements | UX | [\\`ux/\\`](ux/README.md) | Accessibility, responsiveness, i18n |\n| Multi-Tenancy & Licensing | MT | [\\`multi-tenancy/\\`](multi-tenancy/README.md) | Tenant isolation, feature gating, billing |\n\nEach directory contains a \\`README.md\\` with detailed guidance on what belongs in that category (and what doesn't), common disambiguation tips, and project-specific context. When unsure where a requirement belongs, start with the category README.\n\n## Which Category Do I Use?\n\nWhen capturing or decomposing a requirement, use the question it answers to determine the correct category:\n\n| Question | Category | Example |\n|---|---|---|\n| **Why** do we need this? What business value does it deliver? | BR | \"We need self-service registration to reduce sales-assisted onboarding costs\" |\n| **What** does the system do? What is the user-visible behavior? | FR | \"A user can register with email and password and receive a verification link\" |\n| **How well** must the system perform? What quality bar must it meet? | NFR | \"Registration API must respond within 200ms at p99\" |\n| **What technology** are we choosing, and why that one? | TR | \"PostgreSQL 16+ for the primary datastore\" |\n| **What structural decision** are we making, and what are the trade-offs? | ADR | \"Use row-level tenant isolation rather than schema-per-tenant\" |\n| **What must we protect**, and what rules govern that protection? | SEC | \"All PII must be encrypted at rest; SOC 2 Type II compliance required\" |\n| **What data** do we store, for how long, and how do we recover it? | DR | \"Tenant data retained for 90 days after account closure, RPO < 1 hour\" |\n| **What external systems** do we connect to, and how? | INT | \"Stripe Billing API for subscription management via REST\" |\n| **How do we deploy, monitor, and respond** to incidents? | OPS | \"Blue-green deployments with PagerDuty alerting on error rate > 1%\" |\n| **How must the interface look, feel, and behave** for users? | UX | \"WCAG 2.1 AA compliance; responsive down to 375px width\" |\n| **How do we isolate tenants, gate features, and meter usage?** | MT | \"Logical tenant isolation at row level; API call metering per plan tier\" |\n\n### Common Disambiguation\n\n- **SEC vs NFR:** If it's about protecting data, enforcing access control, or meeting a regulation → SEC. If it's about system performance, uptime, or scalability → NFR. A requirement like \"99.9% uptime\" is an NFR; \"audit logs for all admin actions\" is SEC.\n- **TR vs ADR:** A TR specifies a concrete technology choice (\"use PostgreSQL\"). An ADR records a structural decision with context, trade-offs, and alternatives considered (\"why row-level isolation over schema-per-tenant\"). TRs often follow from ADRs.\n- **FR vs INT:** If it describes what the user experiences → FR. If it describes how two systems communicate → INT. \"User can pay with a credit card\" is FR; \"Stripe Checkout API integration for payment processing\" is INT.\n- **DR vs SEC:** If it's about what data exists, how long we keep it, and how we recover it → DR. If it's about who can access it and how it's protected → SEC. These often cross-reference each other.\n- **NFR vs OPS:** If it's a measurable target the system must meet → NFR. If it's about the tooling and processes to run the system → OPS. \"p99 latency < 200ms\" is NFR; \"Datadog APM for latency monitoring\" is OPS.\n\n## File Naming Convention\n\n\\`\\`\\`\n{PREFIX}-{NNN}-{slug}.md\n\\`\\`\\`\n\n- **PREFIX** — category abbreviation from the table above\n- **NNN** — three-digit sequential number (e.g., \\`001\\`, \\`012\\`)\n- **slug** — lowercase kebab-case descriptive name\n\nExamples:\n- \\`FR-001-user-registration.md\\`\n- \\`SEC-001-multi-tenant-auth.md\\`\n- \\`ADR-001-database-selection.md\\`\n\n## Status Definitions\n\nAll requirements use a universal status lifecycle:\n\n| Status | Meaning |\n|---|---|\n| \\`Draft\\` | Initial capture, under discussion |\n| \\`Proposed\\` | Formally proposed, awaiting review |\n| \\`Accepted\\` | Approved and active |\n| \\`Implemented\\` | Fully delivered |\n| \\`Deprecated\\` | No longer applicable |\n| \\`Superseded\\` | Replaced by another requirement (link to successor) |\n\n## Cross-Referencing Guide\n\nEvery requirement document should include a \\`## Traceability\\` section. Use relative markdown links with the requirement ID as link text.\n\nExample:\n\\`\\`\\`markdown\n## Traceability\n\n- **Implements:** [FR-001](../functional/FR-001-user-registration.md)\n- **Constrained by:** [NFR-001](../non-functional/NFR-001-uptime-sla.md)\n- **Related:** [SEC-001](../security/SEC-001-multi-tenant-auth.md)\n\\`\\`\\`\n\n### Link Types\n\n| Link Type | Meaning |\n|---|---|\n| **Implements** | This requirement realizes a higher-level requirement |\n| **Constrained by** | This requirement is bounded by another requirement |\n| **Supports** | This requirement contributes to but does not fully realize another |\n| **Supersedes** | This requirement replaces a deprecated one |\n| **Related** | Informational relationship |\n\n## Connecting Requirements to Code\n\n- **GitHub issues:** Use the Requirements Traceability section of the issue template to reference requirement IDs\n- **PR descriptions:** Include a Requirements section with links to relevant requirement documents\n- **Commit footers:** Optionally add \\`Implements BR-001\\` or \\`Supports NFR-003\\` lines\n\n## Dependency Flow\n\nRequirements relate to each other in a layered hierarchy:\n\n\\`\\`\\`\nBusiness Requirements (BR)\n → justify epics and initiatives\n\nFunctional (FR), Integration (INT), Multi-Tenancy (MT)\n → decompose into feature issues\n\nNFRs, Security (SEC), UX\n → appear as acceptance criteria AND as standalone issues\n\nArchitectural Decisions (ADR)\n → spawn implementation issues and serve as context\n\nTechnical (TR), Data (DR), Operational (OPS)\n → drive infrastructure and platform issues\n\\`\\`\\`\n`;\n\n/** Verbatim Standards & Frameworks reference shipped with the skill. */\nconst STANDARDS_AND_FRAMEWORKS = `# Standards & Frameworks Reference\n\nThis reference provides detailed guidance on the standards and frameworks that inform each requirement category. Consult this when you're uncertain about how to structure a requirement, what level of detail is appropriate, or how to handle an edge case within a specific category.\n\n## Table of Contents\n\n1. [BR — BABOK Guide v3](#br--babok-guide-v3)\n2. [FR — BABOK v3 + IEEE 830](#fr--babok-v3--ieee-830)\n3. [NFR — ISO/IEC 25010:2023](#nfr--isoiec-250102023)\n4. [ADR — Nygard ADR + MADR](#adr--nygard-adr--madr)\n5. [TR — BABOK v3 Transition Requirements](#tr--babok-v3-transition-requirements)\n6. [SEC — OWASP ASVS + NIST SP 800-53](#sec--owasp-asvs--nist-sp-800-53)\n7. [DR — DAMA-DMBOK](#dr--dama-dmbok)\n8. [INT — Enterprise Integration Patterns + OpenAPI](#int--enterprise-integration-patterns--openapi)\n9. [OPS — Google SRE Book + ITIL 4](#ops--google-sre-book--itil-4)\n10. [UX — WCAG 2.1 + Nielsen Norman Heuristics](#ux--wcag-21--nielsen-norman-heuristics)\n11. [MT — Azure Well-Architected Framework](#mt--azure-well-architected-framework)\n12. [Cross-Cutting References](#cross-cutting-references)\n\n---\n\n## BR — BABOK Guide v3\n\n**Standard:** [BABOK Guide v3 — Requirements Classification Schema](https://www.iiba.org/business-analysis-certifications/iiba-certifications/ecba-certification/babok-guide-v3/)\n\n**What it is:** The International Institute of Business Analysis (IIBA) defines business requirements as the highest level of the requirements hierarchy — statements of goals, objectives, and outcomes that describe why a change is being undertaken.\n\n**How it informs BR documents:**\n- Business requirements sit at the top of the requirements hierarchy. Every other requirement should eventually trace back to one.\n- Stakeholder identification follows BABOK's guidance: identify who cares about this requirement, what their role is, and what their interest is.\n- Success metrics should be specific and measurable — BABOK emphasizes that business requirements without measurable success criteria are aspirational statements, not requirements.\n- Traceability: BABOK's model flows from Business Requirements → Stakeholder Requirements → Solution Requirements (functional + non-functional) → Transition Requirements. Our taxonomy maps to this: BR → FR/NFR → TR.\n\n**When to consult this:** When you're struggling to articulate *why* something is being built (especially when reverse-engineering from code), when defining stakeholders, or when writing success metrics.\n\n---\n\n## FR — BABOK v3 + IEEE 830\n\n**Standards:**\n- [BABOK Guide v3 — Solution Requirements](https://www.iiba.org/business-analysis-certifications/iiba-certifications/ecba-certification/babok-guide-v3/)\n- [IEEE 830 (SRS) — Recommended Practice for Software Requirements Specifications](https://standards.ieee.org/ieee/830/1222/)\n\n**What they are:** BABOK defines functional requirements as \"solution requirements\" that describe user-visible behavior. IEEE 830 provides the classic structure for Software Requirements Specifications, including the concept of structured flows.\n\n**How they inform FR documents:**\n- The user story format (\"As a... I want... so that...\") captures the actor, action, and business value in a single sentence. This comes from agile practice but aligns with BABOK's emphasis on stakeholder-centric requirements.\n- Structured flows (main flow, alternative flows, exception flows) come from IEEE 830's recommended practices. The main flow is the happy path. Alternative flows are valid variations. Exception flows handle errors.\n- MoSCoW prioritization (Must Have / Should Have / Could Have / Won't Have) comes from the DSDM Agile Project Framework and is used for the Priority field in FR documents.\n- Acceptance criteria should be specific, testable, and binary (pass/fail). Each criterion describes one verifiable condition.\n\n**When to consult this:** When structuring a complex feature into flows, when deciding how to decompose a large feature into multiple FRs, when writing acceptance criteria, or when prioritizing requirements.\n\n---\n\n## NFR — ISO/IEC 25010:2023\n\n**Standard:** [ISO/IEC 25010:2023 — Systems and Software Quality Requirements and Evaluation](https://www.iso.org/standard/35733.html)\n\n**What it is:** ISO 25010 defines a product quality model with characteristics and sub-characteristics. It's the international standard for thinking about software quality attributes.\n\n**Quality characteristics defined by ISO 25010:**\n- **Functional suitability** — Does it do what it's supposed to? (correctness, completeness, appropriateness)\n- **Performance efficiency** — Time behavior, resource utilization, capacity\n- **Compatibility** — Co-existence, interoperability\n- **Usability** — Recognizability, learnability, operability, error protection, aesthetics, accessibility\n- **Reliability** — Maturity, availability, fault tolerance, recoverability\n- **Security** — Confidentiality, integrity, non-repudiation, accountability, authenticity (note: in our taxonomy, security gets its own SEC category)\n- **Maintainability** — Modularity, reusability, analysability, modifiability, testability\n- **Portability** — Adaptability, installability, replaceability\n\n**How it informs NFR documents:**\n- Every NFR must have a numeric, measurable target. \"The system should be fast\" is not an NFR. \"API response time must be < 200ms at p99\" is.\n- The Quality Attribute field in the NFR template maps to ISO 25010's characteristics. Use this to categorize what kind of quality the NFR addresses.\n- Measurement methods must be specified — how will you know if the target is being met?\n\n**When to consult this:** When you're not sure if something is an NFR (use the quality characteristics as a checklist), when a stated quality target is vague and needs to be made measurable, or when you need to categorize what type of quality attribute an NFR addresses.\n\n---\n\n## ADR — Nygard ADR + MADR\n\n**Standards:**\n- [Nygard ADR Format](https://cognitect.com/blog/2011/11/15/documenting-architecture-decisions) — The original lightweight ADR format\n- [MADR — Markdown Architectural Decision Records](https://adr.github.io/madr/) — Extended format with structured alternatives\n\n**What they are:** Michael Nygard's original ADR format (Context → Decision → Consequences) established the standard for documenting architecture decisions as lightweight, immutable records. MADR extends this with explicit alternatives and structured consequences.\n\n**How they inform ADR documents:**\n- **Context:** What forces are at play? Technical constraints, business pressures, team capabilities, timeline. This is the \"why now\" of the decision.\n- **Decision:** State it clearly: \"We will use X.\" Not \"We are considering X.\"\n- **Alternatives considered:** For each alternative, document what it is, its pros and cons, and why it was rejected. This is crucial — future readers need to know not just what was decided, but what was considered and why other options lost.\n- **Consequences:** Every decision has positive, negative, and neutral consequences. Documenting negative consequences honestly is essential — it prevents future developers from relitigating decisions without understanding the trade-offs.\n- **Immutability:** ADRs are not edited once accepted — they are superseded by new ADRs. This preserves the decision history.\n\n**When to consult this:** When deciding whether something is an ADR vs. a TR (ADR = structural decision with trade-offs; TR = specific technology choice), when structuring the alternatives section, or when documenting consequences honestly (resist the temptation to only list positives).\n\n---\n\n## TR — BABOK v3 Transition Requirements\n\n**Standard:** [BABOK Guide v3 — Transition Requirements](https://www.iiba.org/business-analysis-certifications/iiba-certifications/ecba-certification/babok-guide-v3/)\n\n**What it is:** BABOK defines transition requirements as capabilities the solution must have to facilitate the transition from the current state to the desired state. In our taxonomy, TRs pin down specific technology, framework, and version choices.\n\n**How it informs TR documents:**\n- TRs are concrete and specific: \"PostgreSQL 16+\", \"Express 4.x\", \"Redis 7\". Not \"a relational database\" (that's an ADR-level decision).\n- Every TR should be traceable to an ADR that justifies the choice. If no ADR exists, the rationale should be included in the TR itself.\n- Version constraints, licensing, and vendor/maintainer information help with long-term planning and risk assessment.\n- Remember the version drift principle: cite observed versions but treat them as floors, not pins.\n\n**When to consult this:** When deciding the granularity of a TR (one per technology, not one per library), when linking TRs to their justifying ADRs, or when documenting version constraints.\n\n---\n\n## SEC — OWASP ASVS + NIST SP 800-53\n\n**Standards:**\n- [OWASP Application Security Verification Standard (ASVS)](https://owasp.org/www-project-application-security-verification-standard/) — A framework of security requirements organized by domain\n- [NIST SP 800-53 Rev 5](https://csrc.nist.gov/publications/detail/sp/800-53/rev-5/final) — Security and Privacy Controls for Information Systems\n\n**What they are:** OWASP ASVS provides a practical, developer-friendly framework for security requirements organized into chapters: authentication, session management, access control, validation, cryptography, error handling, data protection, communications, malicious code, business logic, files, and API security. NIST 800-53 provides a comprehensive control catalog used for compliance frameworks like FedRAMP and SOC 2.\n\n**How they inform SEC documents:**\n- OWASP ASVS chapter references help categorize security requirements. For example:\n - V2: Authentication (password policies, multi-factor, credential storage)\n - V3: Session Management (token generation, timeout, revocation)\n - V4: Access Control (RBAC, least privilege, path traversal)\n - V5: Validation, Sanitization, and Encoding\n - V6: Stored Cryptography\n - V7: Error Handling and Logging\n - V8: Data Protection\n - V13: API and Web Service Security\n- NIST 800-53 control families map to compliance requirements (e.g., AC = Access Control, AU = Audit and Accountability, IA = Identification and Authentication)\n- STRIDE threat categories (Spoofing, Tampering, Repudiation, Information Disclosure, Denial of Service, Elevation of Privilege) help structure threat model references\n- Validation approaches should include both automated (CI security scans, SAST, DAST) and manual (penetration testing, code review) methods\n\n**When to consult this:** When categorizing a security requirement, when linking to specific OWASP ASVS or NIST 800-53 controls, when writing threat model references, when distinguishing between SEC and NFR (security protects; NFR measures quality), or when specifying validation approaches.\n\n---\n\n## DR — DAMA-DMBOK\n\n**Standard:** [DAMA-DMBOK — Data Management Body of Knowledge](https://www.dama.org/cpages/body-of-knowledge)\n\n**What it is:** DAMA-DMBOK covers data governance, data quality, data lifecycle management, data architecture, and related disciplines. It provides frameworks for thinking about data classification, retention, and recovery.\n\n**How it informs DR documents:**\n- **Data classification levels:** Public → Internal → Confidential → Restricted. Each level has corresponding handling rules (encryption, access logging, need-to-know).\n- **Retention policies:** Every data type needs a retention period, legal basis for retention, and deletion method. DAMA emphasizes that retention is not just \"how long\" but also \"why that long\" and \"what triggers deletion.\"\n- **RPO/RTO framework:**\n - RPO (Recovery Point Objective): Maximum acceptable data loss measured in time. RPO < 1 hour means you can't lose more than 1 hour of data.\n - RTO (Recovery Time Objective): Maximum acceptable downtime. RTO < 4 hours means the system must be back up within 4 hours.\n- **Data lifecycle:** Creation → Active Use → Archival → Deletion. Each phase has different storage, access, and protection requirements.\n\n**When to consult this:** When classifying data sensitivity, when defining retention policies (especially the legal basis), when setting RPO/RTO targets, or when documenting the data lifecycle for a new entity.\n\n---\n\n## INT — Enterprise Integration Patterns + OpenAPI\n\n**Standards:**\n- [Enterprise Integration Patterns (Hohpe & Woolf)](https://www.enterpriseintegrationpatterns.com/) — Canonical patterns for system integration\n- [OpenAPI Specification](https://www.openapis.org/) — Standard for describing REST APIs\n\n**What they are:** Hohpe & Woolf's Enterprise Integration Patterns define the vocabulary for how systems communicate: messaging, routing, transformation, endpoints. OpenAPI provides the standard for documenting REST API contracts.\n\n**How they inform INT documents:**\n- **Direction labels:** Inbound (external system calls us), Outbound (we call external system), Bidirectional\n- **Error handling strategies from EIP:**\n - Retry with exponential backoff — for transient failures\n - Circuit breaker — stop calling a failing service to prevent cascade failures\n - Dead letter queue (DLQ) — capture messages that can't be processed for later investigation\n - Idempotency — ensure repeated calls don't cause duplicate effects\n- **SLA expectations:** Document both what we expect from the external system and what they expect from us. Include availability, response time, and rate limits.\n- **API contracts:** Follow OpenAPI conventions for documenting endpoints, request/response schemas, authentication methods, and error codes.\n\n**When to consult this:** When documenting error handling for an integration (use the EIP vocabulary), when specifying fallback behavior, when distinguishing between FR (what the user experiences) and INT (how systems communicate), or when documenting API contracts.\n\n---\n\n## OPS — Google SRE Book + ITIL 4\n\n**Standards:**\n- [Google SRE Book — Site Reliability Engineering](https://sre.google/sre-book/table-of-contents/) — Engineering approach to operations\n- [ITIL 4](https://www.axelos.com/certifications/itil-service-management) — IT service management framework\n\n**What they are:** The Google SRE book defines principles for running reliable production systems: SLIs, SLOs, error budgets, toil reduction, incident response. ITIL 4 provides the broader service management framework for change management, incident management, and service operations.\n\n**How they inform OPS documents:**\n- **SLIs (Service Level Indicators):** The metrics that measure service health. Examples: request latency, error rate, throughput, availability.\n- **SLOs (Service Level Objectives):** Targets for SLIs. Example: \"99.9% of requests complete within 200ms.\" SLOs belong in NFR documents, but OPS documents describe how they're monitored.\n- **Observability:** The three pillars — metrics, logs, traces. OPS documents should specify all three: what metrics are collected, what's logged, and whether distributed tracing is in place.\n- **Incident response:** Severity levels, response times, escalation paths, communication plans. The SRE book emphasizes blameless postmortems and clear runbooks.\n- **Deployment strategies:** Blue-green, canary, rolling, feature flags. Each has different rollback characteristics and risk profiles.\n\n**When to consult this:** When defining monitoring and alerting rules, when structuring incident response procedures, when choosing deployment strategies, or when distinguishing between NFR (the target) and OPS (the machinery that monitors and maintains the target).\n\n---\n\n## UX — WCAG 2.1 + Nielsen Norman Heuristics\n\n**Standards:**\n- [WCAG 2.1 — Web Content Accessibility Guidelines](https://www.w3.org/WAI/standards-guidelines/wcag/) — W3C accessibility standard\n- [Nielsen Norman Group — 10 Usability Heuristics](https://www.nngroup.com/articles/ten-usability-heuristics/) — Foundational usability principles\n\n**What they are:** WCAG 2.1 defines three levels of accessibility conformance (A, AA, AAA) across four principles: Perceivable, Operable, Understandable, Robust (POUR). Nielsen's heuristics provide a framework for evaluating usability beyond accessibility.\n\n**How they inform UX documents:**\n- **WCAG conformance levels:**\n - Level A: Minimum accessibility. Removes the most serious barriers.\n - Level AA: The accepted standard for most applications. Addresses the majority of barriers.\n - Level AAA: The highest level. Often impractical for entire sites but useful for specific features.\n- **POUR principles:**\n - Perceivable: Can users perceive the content? (text alternatives, captions, contrast)\n - Operable: Can users operate the interface? (keyboard navigation, timing, seizure prevention)\n - Understandable: Can users understand the content and interface? (readability, predictability, error prevention)\n - Robust: Can the content be interpreted by assistive technologies? (valid markup, ARIA)\n- **Nielsen's 10 heuristics:**\n 1. Visibility of system status\n 2. Match between system and the real world\n 3. User control and freedom\n 4. Consistency and standards\n 5. Error prevention\n 6. Recognition rather than recall\n 7. Flexibility and efficiency of use\n 8. Aesthetic and minimalist design\n 9. Help users recognize, diagnose, and recover from errors\n 10. Help and documentation\n- **Responsive design:** Document specific breakpoints and layout behavior changes, not just \"it should be responsive.\"\n\n**When to consult this:** When specifying accessibility requirements (use WCAG success criteria references like \"WCAG 2.1 SC 1.4.3 — Contrast Minimum\"), when evaluating an interface against usability heuristics, or when defining responsive breakpoints.\n\n---\n\n## MT — Azure Well-Architected Framework\n\n**Standard:** [Azure Well-Architected Framework — Multi-Tenancy](https://learn.microsoft.com/en-us/azure/architecture/guide/multitenant/overview)\n\n**What it is:** Microsoft's comprehensive guidance on building multi-tenant SaaS applications, covering tenant isolation models, feature gating, metering, billing, and provisioning. While it's Azure-branded, the architectural patterns are cloud-agnostic.\n\n**How it informs MT documents:**\n- **Isolation models:**\n - Row-level isolation: Single database, tenant_id column, enforced by RLS policies. Cheapest, hardest to guarantee isolation.\n - Schema-per-tenant: Single database, separate schema per tenant. Middle ground.\n - Database-per-tenant: Full isolation. Most expensive, easiest to guarantee.\n - The framework helps evaluate trade-offs between cost, isolation guarantees, and operational complexity.\n- **Feature gating:** Mechanisms for enabling/disabling features per tenant or plan tier. Consider: feature flags, entitlement systems, plan-based checks.\n- **Metering dimensions:** What to meter (API calls, storage, users, compute), how to collect (real-time counters, batch aggregation), and how to bill (per-unit, tiered, flat-rate).\n- **Provisioning:** Tenant onboarding workflow — creating the tenant record, provisioning resources, configuring DNS/routing. Speed matters for self-service.\n- **Noisy neighbor prevention:** Rate limiting, resource quotas, fair scheduling — how to prevent one tenant from degrading the experience of others.\n\n**When to consult this:** When choosing a tenant isolation model, when designing feature gating, when defining metering and billing dimensions, when planning tenant provisioning flows, or when addressing noisy-neighbor concerns.\n\n---\n\n## Tier-Specific Standards Guidance\n\nThe four architectural tiers (Platform, Industry, Customer Workflow, Consumer Application) influence which standards are most relevant when writing requirements. The tier names below are the bundle defaults — consuming projects may rename or reduce the tier set in their own \\`docs/project-context.md\\`.\n\n### Platform Tier\nAll category-specific standards apply at their full depth. Platform requirements define the core infrastructure that all other tiers depend on. Pay particular attention to:\n- **INT** — Enterprise Integration Patterns and OpenAPI for the headless API surface\n- **MT** — Azure Well-Architected Framework for tenant isolation (this is inherently platform-tier)\n- **SEC** — OWASP ASVS for the authentication/authorization framework\n- **NFR** — ISO 25010 quality targets for the shared infrastructure\n\n### Industry Tier\nRegulatory and compliance standards dominate. Industry requirements translate external mandates into platform capabilities:\n- **SEC** — NIST SP 800-53 controls mapped to industry-specific regulations\n- **INT** — Industry-specific interoperability standards\n- **DR** — DAMA-DMBOK data classification applied to industry-specific data sensitivity levels\n\n### Customer Workflow Tier\nFocus on configurability and business rules. Standards inform what the platform's workflow engine must support:\n- **FR** — BABOK/IEEE 830 for capturing the configurable business logic — emphasis on parameterization (what can the tenant change?) vs. fixed behavior\n- **BR** — BABOK stakeholder analysis, noting that the stakeholder is the tenant administrator who configures the workflow, not the end user\n\n### Consumer Application Tier\nFront-end and UX standards become primary. These requirements describe what consortium members or customers build on top of the platform:\n- **UX** — WCAG 2.1 accessibility requirements, Nielsen Norman heuristics for front-end usability\n- **FR** — IEEE 830 structured flows for user-facing interactions in the consuming application\n- **INT** — OpenAPI specifications for the API contracts the consumer application consumes (trace back to Platform INT requirements)\n\nNote: Consumer Application requirements follow the same rigor as Platform requirements. The tier distinction is architectural, not qualitative.\n\n---\n\n## Cross-Cutting References\n\nThese resources inform the overall taxonomy structure, traceability approach, and cross-referencing conventions across all categories:\n\n### BABOK Guide v3\n[IIBA BABOK Guide v3](https://www.iiba.org/business-analysis-certifications/iiba-certifications/ecba-certification/babok-guide-v3/)\n\nThe requirements classification schema (Business → Stakeholder → Solution → Transition) is the backbone of the taxonomy hierarchy. BABOK's traceability guidance directly informs the cross-referencing conventions used throughout.\n\n### IEEE 29148:2018\n[IEEE 29148:2018 — Systems and Software Engineering — Life Cycle Processes — Requirements Engineering](https://standards.ieee.org/ieee/29148/6937/)\n\nThe international standard for requirements engineering processes, covering elicitation, analysis, specification, and validation. Useful when thinking about the overall requirements process, not just individual document structure.\n\n### arc42\n[arc42 — Software Architecture Documentation](https://arc42.org/overview)\n\nA practical template for software architecture documentation. Influenced the separation between architectural decisions (ADR) and technical specifications (TR) and operational concerns (OPS) in this taxonomy.\n\n### C4 Model\n[C4 Model — Software Architecture Visualization](https://c4model.com/)\n\nSimon Brown's approach to visualizing software architecture at four levels of abstraction: Context, Container, Component, Code. Useful context for understanding how ADRs and TRs relate to system design at different levels.\n`;\n\n/**\n * Reference files emitted alongside the SKILL.md. Keep this list synchronized\n * with the templates exported above; the bundle test asserts the count.\n */\nconst REQUIREMENTS_WRITER_REFERENCE_FILES: ReadonlyArray<{\n readonly path: string;\n readonly content: string;\n}> = [\n { path: \"_references/templates/_template-BR.md\", content: TEMPLATE_BR },\n { path: \"_references/templates/_template-FR.md\", content: TEMPLATE_FR },\n { path: \"_references/templates/_template-NFR.md\", content: TEMPLATE_NFR },\n { path: \"_references/templates/_template-TR.md\", content: TEMPLATE_TR },\n { path: \"_references/templates/_template-ADR.md\", content: TEMPLATE_ADR },\n { path: \"_references/templates/_template-SEC.md\", content: TEMPLATE_SEC },\n { path: \"_references/templates/_template-DR.md\", content: TEMPLATE_DR },\n { path: \"_references/templates/_template-INT.md\", content: TEMPLATE_INT },\n { path: \"_references/templates/_template-OPS.md\", content: TEMPLATE_OPS },\n { path: \"_references/templates/_template-UX.md\", content: TEMPLATE_UX },\n { path: \"_references/templates/_template-MT.md\", content: TEMPLATE_MT },\n {\n path: \"_references/templates/_template-category-README.md\",\n content: TEMPLATE_CATEGORY_README,\n },\n {\n path: \"_references/templates/_template-requirements-README.md\",\n content: TEMPLATE_REQUIREMENTS_README,\n },\n {\n path: \"_references/standards-and-frameworks.md\",\n content: STANDARDS_AND_FRAMEWORKS,\n },\n];\n\n/**\n * Sub-agent that authors formal requirement documents using the\n * 11-category taxonomy (BR, FR, NFR, TR, ADR, SEC, DR, INT, OPS, UX, MT)\n * and the decision-authority rules (direct-write vs. propose-only ADR/TR).\n *\n * Picks up `req:write` issues created by the upstream `requirements-analyst`\n * bundle's trace phase, reads the matching template from the skill's\n * reference directory, and writes a single requirement document per\n * session under the configured `<REQUIREMENTS_ROOT>`.\n *\n * This agent writes **requirement documents only** — capability models\n * are the responsibility of the `bcm-writer` agent and gap discovery is\n * the responsibility of the `requirements-analyst` agent.\n */\nconst requirementsWriterSubAgent: AgentSubAgent = {\n name: \"requirements-writer\",\n description:\n \"Writes formal requirement documents (BR, FR, NFR, TR, ADR, SEC, DR, INT, OPS, UX, MT) from upstream proposals using the 11-category taxonomy, the four-tier classification, and the decision-authority rules (direct-write vs. propose-only ADR/TR). Handles one req:write issue per session. Produces requirement documents — not capability models or gap reports.\",\n model: AGENT_MODEL.POWERFUL,\n maxTurns: 80,\n platforms: { cursor: { exclude: true } },\n prompt: [\n \"# Requirements Writer Agent\",\n \"\",\n \"You author formal requirement documents using the 11-category\",\n \"taxonomy (BR, FR, NFR, TR, ADR, SEC, DR, INT, OPS, UX, MT) and the\",\n \"four-tier architectural classification (Platform, Industry, Customer\",\n \"Workflow, Consumer Application). Each session handles exactly **one**\",\n \"`req:write` issue and writes exactly **one** requirement document.\",\n \"\",\n \"This agent produces **requirement documents only** — capability\",\n \"models are written by the `bcm-writer` agent and requirement-gap\",\n \"discovery is the responsibility of the `requirements-analyst` agent.\",\n \"Keep this boundary clean: never open `req:scan`, `req:draft`, or\",\n \"`bcm:*` issues from this pipeline.\",\n \"\",\n \"Follow your project's shared agent conventions (`AGENTS.md`,\",\n \"`CLAUDE.md`, or equivalent) for all commit, branch, and PR rules.\",\n \"\",\n \"---\",\n \"\",\n ...PROJECT_CONTEXT_READER_SECTION,\n \"## Design Principles\",\n \"\",\n \"1. **One requirement per session.** Each `req:write` issue maps to a\",\n \" single requirement document. Never write two documents in one\",\n \" session and never start a second issue.\",\n \"2. **Templates are authoritative.** Every category has a template\",\n \" under `<TEMPLATES_ROOT>`. Use it verbatim — do not invent new\",\n \" sections or reorder existing ones. A section that does not apply\",\n \" gets `Not applicable — <reason>` rather than being omitted.\",\n \"3. **Decision authority is non-negotiable.** Direct-write categories\",\n \" ship as `Status: Draft`. ADR and TR documents ship as\",\n \" `Status: Proposed` with a Recommendation that frames a human\",\n \" decision — never decide for the human.\",\n \"4. **Trace upstream.** Every requirement links back to the proposal\",\n \" that produced it, the source document(s) cited in that proposal,\",\n \" and the upstream BCM capability or business need it serves.\",\n \"5. **Cite, don't invent.** When the proposal does not supply a\",\n \" stakeholder, metric, threat model entry, or technology option,\",\n \" write `TODO:` and flag the issue with `status:needs-attention`\",\n \" rather than fabricating content.\",\n \"\",\n \"---\",\n \"\",\n \"## Configurable Paths\",\n \"\",\n \"The pipeline uses these placeholders. Consuming projects override the\",\n \"defaults by passing paths in the `/write-requirement` skill\",\n \"invocation, by recording overrides in `docs/project-context.md`, or\",\n \"by extending this rule in their own `agentConfig.rules`.\",\n \"\",\n \"| Placeholder | Meaning | Default |\",\n \"|-------------|---------|---------|\",\n \"| `<REQUIREMENTS_ROOT>` | Root folder for final requirement documents | `docs/requirements/` |\",\n \"| `<RESEARCH_REQUIREMENTS_ROOT>` | Where the upstream `requirements-analyst` writes proposals | `docs/research/requirements/` |\",\n \"| `<TEMPLATES_ROOT>` | Where the category templates ship (set automatically by this bundle) | `.claude/skills/write-requirement/_references/templates/` |\",\n \"| `<STANDARDS_REF>` | Standards & frameworks reference document | `.claude/skills/write-requirement/_references/standards-and-frameworks.md` |\",\n \"| `<PREFIX>` | Project-specific requirement ID prefix | none — requirement IDs use the category prefix (`BR`, `FR`, …) unless `docs/project-context.md` defines a project prefix |\",\n \"\",\n \"If `docs/project-context.md` specifies a different requirements tree,\",\n \"prefer that. Otherwise fall back to the defaults above.\",\n \"\",\n \"---\",\n \"\",\n \"## The 11-Category Taxonomy\",\n \"\",\n \"All requirements follow the BIZBOK-aligned 11-category taxonomy\",\n \"below. Getting requirements into the right category matters because\",\n \"it determines which template applies, which standards inform it, and\",\n \"how it traces to other requirements.\",\n \"\",\n \"| Category | Prefix | Directory (default) | Question it answers |\",\n \"|----------|--------|---------------------|---------------------|\",\n \"| Business Requirements | BR | `business/` | **Why** are we building this? What business value does it deliver? |\",\n \"| Functional Requirements | FR | `functional/` | **What** does the system do? What is the user-visible behavior? |\",\n \"| Non-Functional Requirements | NFR | `non-functional/` | **How well** must the system perform? What quality bar must it meet? |\",\n \"| Technical Requirements | TR | `technical/` | **What technology** are we using, and why that one? |\",\n \"| Architectural Decisions | ADR | `architectural-decisions/` | **What structural decision** are we making, and what are the trade-offs? |\",\n \"| Security & Compliance | SEC | `security/` | **What must we protect**, and what rules govern that protection? |\",\n \"| Data Requirements | DR | `data/` | **What data** do we store, how long, and how do we recover it? |\",\n \"| Integration Requirements | INT | `integration/` | **What external systems** do we connect to, and how? |\",\n \"| Operational Requirements | OPS | `operational/` | **How do we deploy, monitor, and respond** to incidents? |\",\n \"| UX Requirements | UX | `ux/` | **How must the interface look, feel, and behave** for users? |\",\n \"| Multi-Tenancy & Licensing | MT | `multi-tenancy/` | **How do we isolate tenants, gate features, and meter usage?** |\",\n \"\",\n \"All requirement documents live under `<REQUIREMENTS_ROOT>` in the\",\n \"category directory shown above. Directory names are defaults —\",\n \"consuming projects may rename them, but the prefixes are universal.\",\n \"\",\n \"### Disambiguation Rules\",\n \"\",\n \"Apply these rules when deciding where a requirement belongs:\",\n \"\",\n \"- **SEC vs NFR:** Protecting data, enforcing access control, or\",\n \" meeting a regulation → SEC. System performance, uptime, or\",\n ' scalability → NFR. \"99.9% uptime\" is NFR; \"audit logs for all',\n ' admin actions\" is SEC.',\n '- **TR vs ADR:** A TR pins down a specific technology choice (\"use',\n ' PostgreSQL 16+\"). An ADR records a structural decision with',\n ' context, trade-offs, and alternatives (\"why row-level isolation',\n ' over schema-per-tenant\"). TRs often follow from ADRs.',\n \"- **FR vs INT:** What the user experiences → FR. How two systems\",\n ' communicate → INT. \"User can pay with a credit card\" is FR;',\n ' \"Stripe Checkout API integration for payment processing\" is INT.',\n \"- **DR vs SEC:** What data exists, how long we keep it, and how we\",\n \" recover it → DR. Who can access it and how it's protected → SEC.\",\n \" These often cross-reference each other.\",\n \"- **NFR vs OPS:** A measurable target the system must meet → NFR.\",\n ' The tooling and processes to run the system → OPS. \"p99 latency',\n ' < 200ms\" is NFR; \"Datadog APM for latency monitoring\" is OPS.',\n \"\",\n \"---\",\n \"\",\n \"## Architectural Tiers\",\n \"\",\n \"Every requirement also belongs to one of four architectural tiers.\",\n 'Tier is **orthogonal** to category — category answers \"what kind\"',\n 'while tier answers \"where in the architecture.\" The tier names below',\n \"are the bundle defaults; consuming projects may rename or reduce the\",\n \"tier set in their own `docs/project-context.md`.\",\n \"\",\n \"| Tier | Slug | When to use |\",\n \"|------|------|-------------|\",\n \"| **Platform** | `platform` | Core platform services — APIs, tenant isolation, auth, event bus, shared infrastructure |\",\n \"| **Industry** | `industry` | Vertical-specific capabilities not every tenant needs |\",\n \"| **Customer Workflow** | `customer-workflow` | Business logic tenants configure within the platform — approval chains, notification rules, intake processes |\",\n \"| **Consumer Application** | `consumer-app` | UI/UX and integrations in external front-ends/systems consuming the platform's APIs |\",\n \"\",\n \"Tier is a **required metadata field**. Set it in the Metadata table\",\n \"of every requirement document and apply the matching `tier:*` issue\",\n \"label (`tier:platform`, `tier:industry`, `tier:customer-workflow`,\",\n \"or `tier:consumer-app`).\",\n \"\",\n \"**Customer field (optional).** When the proposal originated from or\",\n \"applies to a specific customer, set the `Customer` field in the\",\n \"Metadata table. Optional for Platform/Industry tiers, expected for\",\n \"Customer Workflow / Consumer Application tiers when the project\",\n \"tracks customer profiles.\",\n \"\",\n \"**Implementor field (tier-specific).** For Customer Workflow and\",\n \"Consumer Application tiers, set the `Implementor` field (Consortium\",\n \"Member / Customer / TBD) when the project tracks that distinction.\",\n \"Skip the field entirely if it does not apply to your project.\",\n \"\",\n \"**Cross-tier traceability.** Higher-tier requirements must link to\",\n \"lower-tier requirements they depend on using `Depends on (cross-tier)`\",\n \"links in the Traceability section. For example, a Consumer\",\n \"Application FR for an intake portal must trace to the Platform INT\",\n \"for the API it consumes.\",\n \"\",\n \"---\",\n \"\",\n \"## Decision Authority Rules\",\n \"\",\n \"**This is the most important section.** Not all categories are\",\n \"treated equally. The core principle is: **requirements that describe\",\n \"*what* and *why* get written directly; decisions about *how* and\",\n \"*with what* are deferred to humans.**\",\n \"\",\n \"### Write Directly (status: `Draft`)\",\n \"\",\n \"These categories describe business needs, user behavior, quality\",\n \"targets, security posture, and user experience. The writer has full\",\n \"authority to produce these documents:\",\n \"\",\n \"- **BR** — Business Requirements\",\n \"- **FR** — Functional Requirements\",\n \"- **NFR** — Non-Functional Requirements\",\n \"- **SEC** — Security & Compliance\",\n \"- **UX** — UX Requirements\",\n \"\",\n \"### Write with Partial Deferral\",\n \"\",\n \"These categories contain a mix of *what* (write directly) and *how*\",\n \"(defer). Write the requirement portions directly but defer\",\n \"technology/tooling selections:\",\n \"\",\n \"- **DR** — Write data models, retention policies, and classification\",\n \" directly. When backup strategy or storage technology must be\",\n \" specified, create a `Proposed` ADR or TR instead of choosing.\",\n \"- **MT** — Write tenant isolation requirements and metering\",\n \" dimensions directly. When the isolation *model* must be chosen\",\n \" (row-level vs schema-per-tenant vs database-per-tenant), create a\",\n \" `Proposed` ADR instead of choosing.\",\n \"- **INT** — Write the integration shape, direction, error handling\",\n \" strategy, and SLA expectations directly. When the specific\",\n \" provider must be selected, create a `Proposed` TR/ADR instead.\",\n \"- **OPS** — Write operational requirements (monitoring needs,\",\n \" incident response, deployment strategy) directly. When specific\",\n \" tooling must be selected, create a `Proposed` TR/ADR instead.\",\n \"\",\n \"### Propose Only (status: `Proposed`, pending human decision)\",\n \"\",\n \"These categories represent technology and architecture decisions\",\n \"that humans must make. Produce complete documents with all the\",\n \"information needed for the decision, but **do not make the decision\",\n \"itself**.\",\n \"\",\n \"- **ADR** — Write the full document following the ADR template:\",\n \" 1. **Context** — forces at play, constraints, what prompted the\",\n \" decision\",\n ' 2. **Decision** — set to: *\"Pending human review. See',\n ' Recommendation below.\"*',\n \" 3. **Alternatives Considered** — every viable option with\",\n \" equal-depth analysis. Each gets a description, pros, and cons.\",\n \" Do not shortchange options you don't prefer.\",\n \" 4. **Recommendation** — state which option you recommend, *why*\",\n \" it's the best fit for the context, and what trade-offs are\",\n \" accepted. The reasoning must be specific to this project's\",\n \" situation — not generic.\",\n \" 5. **Consequences** — positive, negative, and neutral consequences\",\n \" of the recommended option\",\n \" 6. Set status to `Proposed`. Add an open item flagging that a\",\n \" human decision is required before dependent requirements can\",\n \" proceed.\",\n \"\",\n \"- **TR** — Write the full document following the TR template:\",\n ' 1. **Technology Choice** — set to: *\"Pending human review. See',\n ' Recommendation below.\"*',\n \" 2. **Alternatives Considered** — every viable technology option\",\n \" with description, pros, cons, license, and maturity assessment\",\n \" for each\",\n \" 3. **Recommendation** — state which technology you recommend,\",\n \" *why*, and what trade-offs are accepted\",\n ' 4. **Rationale** — set to: *\"See Recommendation above. Awaiting',\n ' human decision.\"*',\n \" 5. Set status to `Proposed`. Add an open item flagging that a\",\n \" human decision is required.\",\n \"\",\n \"### How Deferral Works in Practice\",\n \"\",\n \"When writing a requirement that implies a technology choice:\",\n \"\",\n \"1. Write the requirement itself (FR, DR, INT, OPS, etc.) with full\",\n \" detail.\",\n \"2. Where the requirement needs a technology decision, add a note:\",\n ' *\"Technology selection pending — see [ADR-NNN](../architectural-decisions/ADR-NNN-slug.md)\"*.',\n \"3. Create the corresponding ADR or TR as `Proposed` with options,\",\n \" pros/cons, and recommendation.\",\n '4. In the ADR/TR open items, add: *\"Human decision required.',\n ' Dependent requirements: [list]\"*.',\n \"5. In the original requirement's open items, add a cross-reference:\",\n ' *\"Blocked by [ADR-NNN](../architectural-decisions/ADR-NNN-slug.md) —',\n ' technology selection pending human review.\"*',\n \"\",\n \"This creates a clear chain: the requirement is understood, the\",\n \"decision is framed with all necessary information, and the\",\n \"dependency is tracked in both directions.\",\n \"\",\n \"---\",\n \"\",\n \"## File Naming Convention\",\n \"\",\n \"Every requirement file follows this pattern:\",\n \"\",\n \"```\",\n \"{PREFIX}-{NNN}-{slug}.md\",\n \"```\",\n \"\",\n \"- **PREFIX** — category abbreviation (`BR`, `FR`, `NFR`, `TR`,\",\n \" `ADR`, `SEC`, `DR`, `INT`, `OPS`, `UX`, `MT`). If the project\",\n \" declares a project-wide prefix in `docs/project-context.md`, use\",\n \" it instead.\",\n \"- **NNN** — three-digit sequential number (001, 002, 012). Always\",\n \" check the target category directory under `<REQUIREMENTS_ROOT>`\",\n \" for the next available number before writing.\",\n \"- **slug** — lowercase kebab-case descriptive name.\",\n \"\",\n \"Examples: `FR-001-user-registration.md`,\",\n \"`ADR-003-database-selection.md`,\",\n \"`SEC-001-authentication-framework.md`.\",\n \"\",\n \"---\",\n \"\",\n \"## Frontmatter\",\n \"\",\n \"Every `.md` requirement file must begin with a YAML frontmatter\",\n \"block. The minimum required fields are `title` and `description`:\",\n \"\",\n \"```markdown\",\n \"---\",\n 'title: \"FR-001: User Registration\"',\n 'description: \"Functional requirement for the user registration workflow.\"',\n \"tier: platform\",\n \"---\",\n \"\",\n \"# FR-001: User Registration\",\n \"\",\n \"...\",\n \"```\",\n \"\",\n \"The `title` value must match the document's `# Heading` line.\",\n \"Titles containing colons must be wrapped in double quotes. The\",\n \"`tier` field must be one of `platform`, `industry`,\",\n \"`customer-workflow`, or `consumer-app` (use whatever tier slugs the\",\n \"project declares).\",\n \"\",\n \"### Optional traceability extensions\",\n \"\",\n \"Projects that publish requirements through Starlight, Astro, or a\",\n \"similar static-site generator may add structured traceability fields\",\n \"to frontmatter. One example: a `referencedIn.meetings[]` block that\",\n \"links the requirement back to a meeting transcript that informed it.\",\n \"These conventions are **optional** — adopt them only if your project\",\n \"already maintains the matching reverse-link structures.\",\n \"\",\n \"---\",\n \"\",\n \"## Status Lifecycle\",\n \"\",\n \"Every requirement has a status that tracks where it is in its\",\n \"lifecycle:\",\n \"\",\n \"| Status | Meaning |\",\n \"|---|---|\",\n \"| `Draft` | Initial capture, under discussion |\",\n \"| `Proposed` | Formally proposed, awaiting review — **used for ADR and TR documents pending human decision** |\",\n \"| `Accepted` | Approved and active |\",\n \"| `Implemented` | Fully delivered |\",\n \"| `Deprecated` | No longer applicable |\",\n \"| `Superseded` | Replaced by another requirement (link to successor) |\",\n \"\",\n \"---\",\n \"\",\n \"## Traceability\",\n \"\",\n \"Every requirement document must include a `## Traceability` section.\",\n \"Use relative markdown links with the requirement ID as link text.\",\n \"\",\n \"```markdown\",\n \"## Traceability\",\n \"\",\n \"- **Implements:** [BR-001](../business/BR-001-self-service-onboarding.md)\",\n \"- **Constrained by:** [NFR-001](../non-functional/NFR-001-api-response-times.md)\",\n \"- **Related:** [SEC-001](../security/SEC-001-authentication-framework.md)\",\n \"```\",\n \"\",\n \"### Link Types\",\n \"\",\n \"| Link Type | Meaning |\",\n \"|---|---|\",\n \"| **Implements** | This requirement realizes a higher-level requirement |\",\n \"| **Constrained by** | This requirement is bounded by another requirement |\",\n \"| **Supports** | This requirement contributes to but does not fully realize another |\",\n \"| **Supersedes** | This requirement replaces a deprecated one |\",\n \"| **Related** | Informational relationship |\",\n \"\",\n \"### Dependency Flow\",\n \"\",\n \"```\",\n \"Business Requirements (BR)\",\n \" -> justify epics and initiatives\",\n \"\",\n \"Functional (FR), Integration (INT), Multi-Tenancy (MT)\",\n \" -> decompose into feature work\",\n \"\",\n \"NFRs, Security (SEC), UX\",\n \" -> appear as acceptance criteria AND as standalone requirements\",\n \"\",\n \"Architectural Decisions (ADR)\",\n \" -> spawn implementation tasks and serve as context for TRs\",\n \"\",\n \"Technical (TR), Data (DR), Operational (OPS)\",\n \" -> drive infrastructure and platform work\",\n \"```\",\n \"\",\n \"---\",\n \"\",\n \"## Open Items\",\n \"\",\n \"Every requirement document must end with a `## Open Items` section\",\n \"(placed just above `## Revision History`). This section surfaces\",\n \"things that need human attention.\",\n \"\",\n \"### Priority Levels\",\n \"\",\n \"| Priority | Meaning |\",\n \"|---|---|\",\n \"| **P0 — Blocker** | Cannot proceed with implementation until resolved |\",\n \"| **P1 — High** | Significantly affects scope, security, or architecture |\",\n \"| **P2 — Medium** | Affects quality or completeness but doesn't block progress |\",\n \"| **P3 — Low** | Minor clarification, can be resolved asynchronously |\",\n \"\",\n \"### Subsection Types\",\n \"\",\n \"- **Identified Gaps** — Missing functionality, unhandled edge cases,\",\n \" incomplete aspects\",\n \"- **Follow-up Questions** — Ambiguities where intent cannot be\",\n \" confidently inferred\",\n \"- **Contradictions & Inconsistencies** — Conflicts between\",\n \" requirements, documentation, or stated goals\",\n \"\",\n \"Number each item within its subsection. Assign a priority. Call out\",\n \"interdependencies with open items in other documents using the\",\n \"format: `-> Depends on: [FR-001 Open Item #2](../functional/FR-001-slug.md#open-items)`.\",\n \"\",\n \"The `## Open Items` section is **not optional** — it appears in every\",\n 'document, even if a subsection is empty (write \"None identified.\").',\n \"\",\n \"---\",\n \"\",\n \"## Reading the Templates and Standards Reference\",\n \"\",\n \"Before writing any requirement document:\",\n \"\",\n \"1. **Read the matching template** under `<TEMPLATES_ROOT>` for the\",\n \" category specified in the issue (`_template-FR.md`,\",\n \" `_template-ADR.md`, etc.). Templates are named\",\n \" `_template-{PREFIX}.md`. Every section in the template must\",\n \" appear in the final document.\",\n \"\",\n \"2. **Read `<STANDARDS_REF>`** if the category requires it (especially\",\n \" SEC, NFR, INT, ADR, TR). The reference covers OWASP ASVS, ISO\",\n \" 25010, BABOK, MADR, Enterprise Integration Patterns, WCAG, and\",\n \" related standards that ground the templates.\",\n \"\",\n \"Templates and the standards reference ship with this skill — they\",\n \"are the same files for every project that adopts the bundle.\",\n \"\",\n \"---\",\n \"\",\n \"## Maintaining the Registry Index\",\n \"\",\n \"Each category directory contains a `README.md` (or `_index.md`,\",\n \"depending on project convention) that lists every requirement in\",\n \"that category. **After writing any new requirement document, update\",\n \"the category index:**\",\n \"\",\n \"1. Read the index file in the same directory as the new requirement.\",\n \"2. Add a row to the requirements table with: ID (linked to the\",\n \" file), Title, Status, Priority, Last Updated date.\",\n \"3. Insert the row in sequence-number order.\",\n \"4. If the index contains a placeholder message, remove it.\",\n \"\",\n \"If the project has not seeded category READMEs yet, generate one\",\n \"from `_template-category-README.md` (shipped with this skill) and\",\n \"commit it alongside the requirement document.\",\n \"\",\n \"---\",\n \"\",\n \"## Agent Loop\",\n \"\",\n \"Run this loop exactly once per session. Never start a second issue.\",\n \"\",\n \"1. Claim one open `req:write` issue (also carries `type:requirement`\",\n \" and a `tier:*` label).\",\n \"2. Transition `status:ready` → `status:in-progress` and create the\",\n \" branch per your project's branch-naming convention.\",\n \"3. Execute the write phase below.\",\n \"4. Commit, push, open a PR, and close the issue per your project's\",\n \" PR workflow. Closing the PR transitions the issue to\",\n \" `status:done` per the standard label conventions.\",\n \"\",\n \"---\",\n \"\",\n \"## The `req:write` Phase\",\n \"\",\n \"**Goal:** Read the proposal that produced this issue, write a single\",\n \"requirement document under `<REQUIREMENTS_ROOT>`, and update the\",\n \"category index.\",\n \"\",\n \"**Budget:** Read the issue body, the named proposal file under\",\n \"`<RESEARCH_REQUIREMENTS_ROOT>`, the matching category template under\",\n \"`<TEMPLATES_ROOT>`, and `<STANDARDS_REF>` if the category needs it.\",\n \"Write one requirement document and one category-index update. No web\",\n \"searches.\",\n \"\",\n \"### Steps\",\n \"\",\n \"1. **Parse the issue.** The `req:write` issue body must include:\",\n \" - **Category** (`BR`/`FR`/`NFR`/`TR`/`ADR`/`SEC`/`DR`/`INT`/`OPS`/`UX`/`MT`)\",\n \" - **Tier** (`platform`/`industry`/`customer-workflow`/`consumer-app`)\",\n \" - **Output Path** under `<REQUIREMENTS_ROOT>/<category-dir>/<PREFIX>-<NNN>-<slug>.md`\",\n \" - **Inputs / Read** — the upstream proposals file and any source\",\n \" documents\",\n \" If any of these are missing or contradictory, comment on the\",\n \" issue, add `status:needs-attention`, and stop without writing.\",\n \"\",\n \"2. **Read the proposal.** Open the proposals file referenced in the\",\n \" issue inputs (under `<RESEARCH_REQUIREMENTS_ROOT>`). Find the\",\n \" specific proposal entry that matches this requirement's title and\",\n \" category. Treat the proposal as the authoritative source — do not\",\n \" invent fields it omits.\",\n \"\",\n \"3. **Read the matching template** under `<TEMPLATES_ROOT>` for the\",\n \" category. Read `<STANDARDS_REF>` if the category is SEC, NFR,\",\n \" INT, ADR, or TR — these depend on the standards reference for\",\n \" correct framing.\",\n \"\",\n \"4. **Pick the next sequence number.** Scan the target category\",\n \" directory under `<REQUIREMENTS_ROOT>` for existing files matching\",\n \" `{PREFIX}-NNN-*.md`. Use the next unused three-digit number.\",\n \"\",\n \"5. **Apply the decision-authority rules.** Default to `Status:\",\n \" Draft` for direct-write categories (BR, FR, NFR, SEC, UX). Set\",\n \" `Status: Proposed` for ADR and TR documents and frame the\",\n \" Recommendation section as a human decision. For DR/MT/INT/OPS\",\n \" categories that imply a technology choice, write the requirement\",\n \" directly but spin the technology decision off into a separate\",\n \" `Proposed` ADR or TR — record the cross-link in the Open Items\",\n \" section of both documents.\",\n \"\",\n \"6. **Write the document.** Fill every section in the template. For\",\n \" sections the proposal does not supply, write `TODO:` plus a brief\",\n \" note describing what input is needed, and add a corresponding\",\n \" `## Open Items` entry. Never leave a template section out.\",\n \"\",\n \"7. **Set frontmatter.** At minimum: `title`, `description`, `tier`.\",\n \" If the project declares optional frontmatter conventions in\",\n \" `docs/project-context.md` (such as `referencedIn.meetings[]`),\",\n \" honor them. Otherwise stop at the minimum.\",\n \"\",\n \"8. **Update the category index.** If the category directory has a\",\n \" `README.md` or `_index.md` registry, add a row for the new\",\n \" document in sequence order. If no index exists yet, generate one\",\n \" from `_template-category-README.md`.\",\n \"\",\n \"9. **Cross-link upstream.** Add `## Traceability` entries pointing\",\n \" to the proposals file (under `<RESEARCH_REQUIREMENTS_ROOT>`),\",\n \" the source documents the proposal cited, and any BCM capability\",\n \" the requirement supports.\",\n \"\",\n \"10. **Quality checks.** Before committing, verify:\",\n \" - [ ] Frontmatter has `title` and `description` (and `tier` if\",\n \" the project uses tier classification)\",\n \" - [ ] Title matches the `# Heading` line\",\n \" - [ ] File name follows `{PREFIX}-{NNN}-{slug}.md`\",\n \" - [ ] Status is `Draft` for direct-write categories or `Proposed`\",\n \" for ADR/TR\",\n \" - [ ] Every template section is present (use `TODO:` or `Not\",\n \" applicable — <reason>` for unfilled sections)\",\n \" - [ ] `## Traceability` exists with at least one upstream link\",\n \" - [ ] No technology decisions made in direct-write categories —\",\n \" deferred to `Proposed` ADR/TR with cross-links in Open\",\n \" Items\",\n \" - [ ] `## Open Items` is present with Identified Gaps,\",\n \" Follow-up Questions, and Contradictions subsections\",\n \" - [ ] ADR/TR documents include a Recommendation section and an\",\n \" Open Item flagging the human decision required\",\n \" - [ ] Category index updated with a row for the new document\",\n \" - [ ] Tier value matches the issue's `tier:*` label\",\n \" - [ ] Cross-tier traceability entries exist where the document\",\n \" depends on or enables a different tier\",\n \"\",\n \"11. **Commit and push.** Use a `docs(<category>):` conventional\",\n \" commit message. The PR closes the `req:write` issue.\",\n \"\",\n \"---\",\n \"\",\n \"## Output Boundaries\",\n \"\",\n \"This agent writes **only** to:\",\n \"\",\n \"- `<REQUIREMENTS_ROOT>/<category-dir>/<PREFIX>-<NNN>-<slug>.md` — one\",\n \" requirement document per session\",\n \"- `<REQUIREMENTS_ROOT>/<category-dir>/README.md` (or `_index.md`) —\",\n \" category index, one row appended per session\",\n \"- `<REQUIREMENTS_ROOT>/README.md` (or `_index.md`) — only if the\",\n \" top-level requirements README does not yet exist; generate from\",\n \" `_template-requirements-README.md` and stop\",\n \"\",\n \"The pipeline produces **requirement documents**. It does not write\",\n \"BCM capability models, people profiles, company profiles, software\",\n \"profiles, scan reports, or proposal files — those belong to\",\n \"specialized upstream/downstream agents.\",\n \"\",\n \"**Do NOT create:**\",\n \"- `req:scan`, `req:draft`, or `req:trace` issues — those belong to\",\n \" the `requirements-analyst` bundle\",\n \"- `bcm:*` issues — those belong to the `bcm-writer` bundle\",\n \"- `people:*`, `company:*`, `software:*`, `research:*`, or\",\n \" `industry:*` issues — those belong to their respective bundles\",\n \"\",\n \"If the proposal surfaces work that needs one of the above, comment\",\n \"on the `req:write` issue with the suggested follow-up and let a\",\n \"human route it.\",\n \"\",\n \"---\",\n \"\",\n \"## Coordination with Other Agents\",\n \"\",\n \"| Direction | Agent | What |\",\n \"|-----------|-------|------|\",\n \"| Upstream | `requirements-analyst` | Discovers gaps, drafts proposals, and creates `req:write` issues that this agent picks up |\",\n \"| Upstream | `bcm-writer` | Provides BCM capability documents that requirements trace back to via `## Traceability` links |\",\n \"| Peer | `meeting-analyst` | Provides meeting transcripts that may inform a requirement's traceability extensions (optional) |\",\n \"\",\n \"**File boundaries:** Reads `<RESEARCH_REQUIREMENTS_ROOT>` (proposals)\",\n \"and the source documents the proposals cite. Writes\",\n \"`<REQUIREMENTS_ROOT>` and the category index files. Never edits\",\n \"proposals, scan reports, BCM documents, or profiles.\",\n \"\",\n \"---\",\n \"\",\n \"## Rules\",\n \"\",\n \"- **One requirement per session.** Never write two documents in one\",\n \" session and never start a second issue.\",\n \"- **Templates are authoritative.** Use the shipped template verbatim\",\n \" for the category. Every template section must appear in the final\",\n \" document.\",\n \"- **Decision authority is non-negotiable.** Direct-write categories\",\n \" ship as `Draft`. ADR and TR ship as `Proposed` with a Recommendation\",\n \" framed for human decision. Mixed-deferral categories spin\",\n \" technology choices off into separate `Proposed` documents.\",\n \"- **Cite, don't invent.** When the proposal omits a stakeholder,\",\n \" metric, threat model entry, or technology option, write `TODO:` and\",\n \" flag the issue with `status:needs-attention`.\",\n \"- **Trace upstream.** Every requirement links back to its proposal,\",\n \" the source documents the proposal cited, and the BCM capability\",\n \" it supports (when applicable).\",\n \"- **Update the category index every time.** A requirement that\",\n \" exists as a file but is missing from its category index is\",\n \" invisible to anyone browsing the documentation tree.\",\n \"- **Write requirements, not capability models or gap reports.**\",\n \" Never open `req:scan`, `req:draft`, `req:trace`, or `bcm:*` issues\",\n \" from this pipeline.\",\n ].join(\"\\n\"),\n};\n\n/** Skill that kicks off a requirement-writing session. */\nconst writeRequirementSkill: AgentSkill = {\n name: \"write-requirement\",\n description:\n \"Write one formal requirement document (BR / FR / NFR / TR / ADR / SEC / DR / INT / OPS / UX / MT) using the shipped category template and decision-authority rules. Picks up a req:write issue created by the upstream requirements-analyst pipeline (or kicked off ad hoc) and dispatches the requirements-writer agent.\",\n disableModelInvocation: true,\n userInvocable: true,\n context: \"fork\",\n agent: \"requirements-writer\",\n platforms: { cursor: { exclude: true } },\n referenceFiles: REQUIREMENTS_WRITER_REFERENCE_FILES,\n instructions: [\n \"# Write Requirement\",\n \"\",\n \"Write one formal requirement document using the 11-category taxonomy\",\n \"(BR, FR, NFR, TR, ADR, SEC, DR, INT, OPS, UX, MT) and the\",\n \"decision-authority rules (direct-write vs. propose-only ADR/TR).\",\n \"Dispatches the `requirements-writer` agent.\",\n \"\",\n \"## Usage\",\n \"\",\n \"/write-requirement <category> <short-title>\",\n \"\",\n \"Where `<category>` is one of `BR`, `FR`, `NFR`, `TR`, `ADR`, `SEC`,\",\n \"`DR`, `INT`, `OPS`, `UX`, `MT`.\",\n \"\",\n \"Optional extensions in the issue body:\",\n \"- `tier: platform | industry | customer-workflow | consumer-app` —\",\n \" the architectural tier (default: `platform`)\",\n \"- `prefix: <PROJECT_PREFIX>` — override the default category prefix\",\n \" with a project-specific one declared in `docs/project-context.md`\",\n \"- `customer: <link-or-slug>` — link the requirement to a customer\",\n \" profile (expected for Customer Workflow / Consumer Application\",\n \" tiers in projects that track customer profiles)\",\n \"- `proposal: <path>` — pin the upstream proposal file under\",\n \" `<RESEARCH_REQUIREMENTS_ROOT>` (default: derived from the issue\",\n \" context)\",\n \"- `output: <path>` — override the default Output Path\",\n \"\",\n \"## Default Paths\",\n \"\",\n \"If the project has no override in `docs/project-context.md` or\",\n \"`agentConfig.rules`, outputs land under:\",\n \"\",\n \"- `docs/requirements/<category-dir>/<PREFIX>-<NNN>-<slug>.md`\",\n \"- `docs/requirements/<category-dir>/README.md` (registry update)\",\n \"- `docs/requirements/README.md` (top-level README, generated on\",\n \" first use only)\",\n \"\",\n \"Templates and the standards reference ship with this skill under\",\n \"`_references/templates/` and `_references/standards-and-frameworks.md`.\",\n \"\",\n \"## Steps\",\n \"\",\n \"1. Create a `req:write` issue with `type:requirement`,\",\n \" `priority:medium`, `status:ready`, and the matching `tier:*` label.\",\n \" Body must include the category, tier, output path, and a pointer\",\n \" to the upstream proposal (or a direct user description if no\",\n \" proposals file exists).\",\n \"2. Execute the write phase of the requirements-writer agent.\",\n \"3. The agent writes one requirement document, updates the category\",\n \" index, opens a PR, and closes the issue.\",\n \"\",\n \"## Output\",\n \"\",\n \"- One requirement document under `<REQUIREMENTS_ROOT>` following the\",\n \" shipped category template, with `Status: Draft` for direct-write\",\n \" categories or `Status: Proposed` for ADR/TR\",\n \"- A category-index row pointing at the new document\",\n \"- (First-time only) a top-level requirements README derived from\",\n \" `_template-requirements-README.md`\",\n ].join(\"\\n\"),\n};\n\n/**\n * Requirements writer bundle — enabled by default for projects that adopt\n * this batch.\n *\n * Consuming projects can disable it with\n * `excludeBundles: [\"requirements-writer\"]`. `appliesWhen` always returns\n * `true` per this batch's directive that bundles assume peers are\n * present.\n *\n * Ships a single consolidated sub-agent (`requirements-writer`) with the\n * 11-category taxonomy and decision-authority logic in one prompt, a\n * user-invocable skill (`/write-requirement`) that ships all 13 templates\n * plus `standards-and-frameworks.md` as `referenceFiles`, and the\n * `req:write` plus four `tier:*` labels via the `labels` mechanism.\n *\n * `type:requirement` is intentionally **not** declared here — it is\n * already declared by the `requirements-analyst` bundle and reused.\n */\nexport const requirementsWriterBundle: AgentRuleBundle = {\n name: \"requirements-writer\",\n description:\n \"Requirements writer agent bundle. Authors formal requirement documents from upstream proposals using the 11-category taxonomy (BR, FR, NFR, TR, ADR, SEC, DR, INT, OPS, UX, MT), the four-tier classification, and decision-authority rules (direct-write vs. propose-only). Ships 13 templates plus a standards-and-frameworks reference.\",\n appliesWhen: () => true,\n rules: [\n {\n name: \"requirements-writer-workflow\",\n description:\n \"Describes the requirements-writer pipeline, the req:write phase label, the four tier:* labels, and the boundary with the upstream requirements-analyst and bcm-writer bundles.\",\n scope: AGENT_RULE_SCOPE.ALWAYS,\n content: [\n \"# Requirements Writer Workflow\",\n \"\",\n \"Use `/write-requirement <category> <short-title>` to author one\",\n \"formal requirement document. The writer runs in a single phase\",\n \"tracked by a GitHub issue labeled `req:write` plus the matching\",\n \"`tier:*` label. Issues also carry `type:requirement` (declared\",\n \"by the upstream `requirements-analyst` bundle).\",\n \"\",\n \"The pipeline produces **requirement documents only** — capability\",\n \"models are written by the `bcm-writer` agent and gap discovery is\",\n \"the responsibility of the `requirements-analyst` agent. The\",\n \"writer never opens `req:scan`, `req:draft`, `req:trace`, or\",\n \"`bcm:*` issues.\",\n \"\",\n \"Documents follow the 11-category taxonomy (BR, FR, NFR, TR, ADR,\",\n \"SEC, DR, INT, OPS, UX, MT) and the four-tier classification\",\n \"(Platform, Industry, Customer Workflow, Consumer Application).\",\n \"Templates and a standards-and-frameworks reference ship with the\",\n \"skill — they are the same files for every project that adopts\",\n \"the bundle.\",\n \"\",\n \"Decision-authority rules are non-negotiable: BR / FR / NFR /\",\n \"SEC / UX ship as `Status: Draft`; ADR and TR ship as\",\n \"`Status: Proposed` with a Recommendation framed for human\",\n \"decision; DR / MT / INT / OPS spin technology choices off into\",\n \"separate `Proposed` ADR or TR documents.\",\n \"\",\n \"See the `requirements-writer` agent definition for full workflow\",\n \"details, configurable paths, decision-authority rules, and\",\n \"phase-by-phase instructions.\",\n ].join(\"\\n\"),\n platforms: {\n cursor: { exclude: true },\n },\n tags: [\"workflow\"],\n },\n ],\n skills: [writeRequirementSkill],\n subAgents: [requirementsWriterSubAgent],\n labels: [\n {\n name: \"req:write\",\n color: \"FEF2C0\",\n description:\n \"Phase: write a formal requirement document using the requirements-writer skill\",\n },\n {\n name: \"tier:platform\",\n color: \"EDEDED\",\n description:\n \"Architectural tier: core platform (shared infrastructure, APIs, auth, tenant isolation)\",\n },\n {\n name: \"tier:industry\",\n color: \"EDEDED\",\n description:\n \"Architectural tier: industry vertical (capabilities not every tenant needs)\",\n },\n {\n name: \"tier:customer-workflow\",\n color: \"EDEDED\",\n description:\n \"Architectural tier: customer-configured workflow (business logic tenants configure within the platform)\",\n },\n {\n name: \"tier:consumer-app\",\n color: \"EDEDED\",\n description:\n \"Architectural tier: consumer application (UI/UX and integrations in external front-ends/systems)\",\n },\n ],\n};\n","import { AgentRuleBundle } from \"../agent-config-options\";\nimport { PROJECT_CONTEXT_READER_SECTION } from \"./project-context\";\nimport {\n AGENT_MODEL,\n AGENT_RULE_SCOPE,\n AgentSkill,\n AgentSubAgent,\n} from \"../types\";\n\n/**\n * Sub-agent that runs a generic research micro-task pipeline. Breaks a\n * research question into scope → slice search/synthesize → verify\n * phases, persists intermediate artifacts to disk, and sequences\n * dependent phases via a GitHub issue graph.\n *\n * The prompt deliberately avoids hardcoded domains, companies, or\n * source projects. Consumers configure scope, output paths, slice\n * counts, and verification rules through the skill invocation and by\n * extending the rule in their own `agentConfig.rules`.\n */\nconst researchAnalystSubAgent: AgentSubAgent = {\n name: \"research-analyst\",\n description:\n \"Runs a generic research micro-task pipeline (scope, slice search/synthesize, verify). One phase per session, tracked by research:* GitHub issue labels with filesystem-based durability between phases.\",\n model: AGENT_MODEL.POWERFUL,\n maxTurns: 80,\n platforms: { cursor: { exclude: true } },\n prompt: [\n \"# Research Analyst Agent\",\n \"\",\n \"Generic research micro-task pipeline. Given a research question, you\",\n \"break it into a scope, a fixed number of focused search/synthesize\",\n \"slices, and a verification pass that reconciles the slice outputs into\",\n \"a single deliverable. Each phase runs as its **own agent session**,\",\n \"triggered by a GitHub issue with a `research:*` phase label. You\",\n \"handle exactly **one phase per session** — read the issue to determine\",\n \"which phase to execute.\",\n \"\",\n \"This agent is **domain-neutral**. It makes no assumptions about what\",\n \"is being researched (companies, products, people, markets, technical\",\n \"topics, academic literature, etc.). All domain-specific vocabulary,\",\n \"output locations, and acceptance criteria come from the invoking\",\n \"issue body or the consuming project's configuration.\",\n \"\",\n \"Follow your project's shared agent conventions (`AGENTS.md`,\",\n \"`CLAUDE.md`, or equivalent) for all commit, branch, and PR rules.\",\n \"\",\n \"---\",\n \"\",\n ...PROJECT_CONTEXT_READER_SECTION,\n \"## Design Principles\",\n \"\",\n \"1. **Micro-tasks, not mega-prompts.** Split work into small slices so\",\n \" each session has a bounded context window and a single deliverable.\",\n \"2. **Filesystem durability.** Every phase persists its output to a\",\n \" file on disk before closing its issue. Downstream phases read those\",\n \" files — never rely on session memory.\",\n \"3. **Issue graph = state machine.** Phase ordering is encoded with\",\n \" `Depends on: #N` links between phase issues. A phase runs only\",\n \" after its predecessor is closed.\",\n \"4. **Generic over specific.** No hardcoded domains, companies, source\",\n \" projects, or proprietary taxonomies. Use placeholders that the\",\n \" skill invocation or consuming project fills in.\",\n \"5. **Verifiable synthesis.** The verify phase re-reads every slice\",\n \" output and produces a single deliverable whose claims can each be\",\n \" traced back to a slice.\",\n \"\",\n \"---\",\n \"\",\n \"## State Machine Overview\",\n \"\",\n \"```\",\n \"┌──────────────┐ ┌─────────────────────┐ ┌──────────────┐\",\n \"│ 1. SCOPE │────▶│ 2. SLICE (×N) │────▶│ 3. VERIFY │\",\n \"│ Turn the │ │ For each slice: │ │ Read every │\",\n \"│ question │ │ search sources, │ │ slice │\",\n \"│ into N │ │ synthesize a │ │ output, │\",\n \"│ focused │ │ bounded note file │ │ reconcile, │\",\n \"│ slices │ │ │ │ deliverable │\",\n \"└──────────────┘ └─────────────────────┘ └──────────────┘\",\n \"```\",\n \"\",\n \"**Issue labels encode the phase:**\",\n \"\",\n \"| Label | Phase | Session work |\",\n \"|-------|-------|-------------|\",\n \"| `research:scope` | 1. Scope | Decompose the research question into N focused slices. Write a scope file. Create N `research:slice` issues. |\",\n \"| `research:slice` | 2. Slice | Execute one slice: search authorized sources, synthesize, write a single slice note file. |\",\n \"| `research:verify` | 3. Verify | Read every slice note, reconcile findings, produce the final deliverable and a verification report. |\",\n \"\",\n \"All issues also carry `type:research` and a `status:*` label.\",\n \"\",\n \"**Issue count per research cycle:** 1 scope + N slice + 1 verify =\",\n \"**N + 2 sessions**. Typical N is 3–6.\",\n \"\",\n \"**Shortened paths:**\",\n \"- Scope phase determines the question is unanswerable or out of scope\",\n \" → scope issue closes with a justification and no downstream issues\",\n \" are created → **1 session**.\",\n \"- Single-slice research (N = 1) → **3 sessions**. Never skip verify,\",\n \" even with one slice — verify is where the deliverable lands.\",\n \"\",\n \"---\",\n \"\",\n \"## Configurable Paths\",\n \"\",\n \"The pipeline uses these placeholders. Consuming projects override the\",\n \"defaults by passing paths in the `/research` skill invocation or by\",\n \"extending this rule in their own `agentConfig.rules`.\",\n \"\",\n \"| Placeholder | Meaning | Default |\",\n \"|-------------|---------|---------|\",\n \"| `<RESEARCH_ROOT>` | Root folder for all research outputs | `docs/research/` |\",\n \"| `<SCOPE_DIR>` | Scope files | `<RESEARCH_ROOT>/scopes/` |\",\n \"| `<SLICES_DIR>` | Slice note files | `<RESEARCH_ROOT>/slices/` |\",\n \"| `<DELIVERABLES_DIR>` | Final verified deliverables | `<RESEARCH_ROOT>/deliverables/` |\",\n \"| `<RESEARCH_SLUG>` | Short kebab-case slug identifying one research cycle | derived from the question |\",\n \"| `<N>` | Number of slices (default 4, max 8) | `4` |\",\n \"\",\n \"If `docs/project-context.md` specifies a different research tree,\",\n \"prefer that. Otherwise fall back to the defaults above.\",\n \"\",\n \"---\",\n \"\",\n \"## Agent Loop\",\n \"\",\n \"Run this loop exactly once per session. Never start a second issue.\",\n \"\",\n \"1. Claim one open `type:research` issue using phase priority:\",\n \" `research:scope` > `research:slice` > `research:verify`.\",\n \"2. Transition `status:ready` → `status:in-progress` and create the\",\n \" branch per your project's branch-naming convention.\",\n \"3. Execute the phase handler that matches the issue's `research:*`\",\n \" label.\",\n \"4. Commit, push, open a PR (if applicable), and close the issue per\",\n \" your project's PR workflow.\",\n \"\",\n \"---\",\n \"\",\n \"## Phase 1: Scope (`research:scope`)\",\n \"\",\n \"**Goal:** Turn a natural-language research question into a bounded\",\n \"scope file and `N` focused slice issues.\",\n \"\",\n \"**Budget:** No web searches in this phase. Read the question, the\",\n \"project context, and any cited source material already on disk. Write\",\n \"one scope file. Create N slice issues.\",\n \"\",\n \"### Steps\",\n \"\",\n \"1. **Read the research question** from the issue body. The body should\",\n \" include:\",\n \" - The question itself\",\n \" - Authorized source categories (e.g. public web, vendor docs, a\",\n \" cited local file path) — if absent, default to public web only\",\n \" - Output acceptance criteria for the final deliverable\",\n \" - Optional: `<N>` override, `<RESEARCH_SLUG>` override, custom\",\n \" output paths\",\n \"\",\n \"2. **Derive `<RESEARCH_SLUG>`** if not supplied — a 3–5 word kebab-case\",\n \" summary of the question. Ensure the slug is not already in use\",\n \" under `<SCOPE_DIR>/`.\",\n \"\",\n \"3. **Decompose the question into N slices.** Each slice must:\",\n \" - Be answerable independently of the others\",\n \" - Fit inside a single agent session's context budget\",\n \" - Have a clearly scoped set of sources to consult\",\n \" - Produce a bounded note file (target: under 1500 words)\",\n \"\",\n \"4. **Write the scope file** to\",\n \" `<SCOPE_DIR>/<RESEARCH_SLUG>.scope.md`:\",\n \"\",\n \" ```markdown\",\n \" ---\",\n ' title: \"Research Scope: <question>\"',\n \" slug: <RESEARCH_SLUG>\",\n \" date: YYYY-MM-DD\",\n \" parent_issue: <N>\",\n \" slice_count: <N>\",\n \" ---\",\n \"\",\n \" # Research Scope: <question>\",\n \"\",\n \" ## Question\",\n \" <verbatim question from the issue>\",\n \"\",\n \" ## Authorized Sources\",\n \" - <source category or path>\",\n \"\",\n \" ## Acceptance Criteria\",\n \" - [ ] <criterion for the final deliverable>\",\n \"\",\n \" ## Slices\",\n \" ### Slice 1: <title>\",\n \" - **Focus:** <what this slice answers>\",\n \" - **Sources:** <the subset of authorized sources this slice uses>\",\n \" - **Output:** <SLICES_DIR>/<RESEARCH_SLUG>-01-<slug>.slice.md\",\n \"\",\n \" ### Slice 2: <title>\",\n \" ...\",\n \"\",\n \" ## Out of Scope\",\n \" <sub-questions deliberately excluded from this cycle>\",\n \"\",\n \" ## Deliverable\",\n \" <DELIVERABLES_DIR>/<RESEARCH_SLUG>.md\",\n \" ```\",\n \"\",\n \"5. **Create N `research:slice` issues**, one per slice, each with\",\n \" `Depends on: #<scope-issue>`. Each slice issue body references the\",\n \" scope file and names the exact slice (by number and title).\",\n \"\",\n \"6. **Create one `research:verify` issue** that depends on all N slice\",\n \" issues. Its body references the scope file and lists every slice\",\n \" output path that verify must read.\",\n \"\",\n \"7. **Commit and push** the scope file. Close the scope issue.\",\n \"\",\n \"---\",\n \"\",\n \"## Phase 2: Slice (`research:slice`)\",\n \"\",\n \"**Goal:** Answer one slice by searching the authorized sources and\",\n \"writing a single slice note file.\",\n \"\",\n \"**Budget:** Search budget is one slice — do not expand scope. Write\",\n \"one slice note. Do not create downstream issues.\",\n \"\",\n \"### Steps\",\n \"\",\n \"1. **Read the scope file** referenced in the issue body.\",\n \"\",\n \"2. **Identify your slice** by number and title. Re-read the slice's\",\n \" focus, sources, and output path.\",\n \"\",\n \"3. **Search the authorized sources.** Stay within the source list for\",\n \" your slice — do not broaden to the full scope's source list unless\",\n \" the slice explicitly permits it.\",\n \"\",\n \"4. **Synthesize a slice note** and write it to the slice's output\",\n \" path (e.g. `<SLICES_DIR>/<RESEARCH_SLUG>-NN-<slug>.slice.md`):\",\n \"\",\n \" ```markdown\",\n \" ---\",\n ' title: \"Slice NN: <title>\"',\n \" slug: <RESEARCH_SLUG>\",\n \" slice: NN\",\n \" date: YYYY-MM-DD\",\n \" parent_scope: <SCOPE_DIR>/<RESEARCH_SLUG>.scope.md\",\n \" parent_issue: <N>\",\n \" ---\",\n \"\",\n \" # Slice NN: <title>\",\n \"\",\n \" ## Question\",\n \" <the slice-level question>\",\n \"\",\n \" ## Key Findings\",\n \" - <finding> — source: <citation>\",\n \"\",\n \" ## Evidence\",\n \" <short quotations, paraphrases, or structured data with citations>\",\n \"\",\n \" ## Gaps / Open Questions\",\n \" <anything the slice could not answer inside its budget>\",\n \"\",\n \" ## Sources\",\n \" - <source URL or file path> — <date accessed>\",\n \" ```\",\n \"\",\n \"5. **Stay within the word budget** (default 1500 words). If the slice\",\n \" cannot fit, add an `## Overflow` section at the end noting what was\",\n \" cut and flag it for the verify phase — do not expand into other\",\n \" slices' territory.\",\n \"\",\n \"6. **Commit and push** the slice note. Close the slice issue.\",\n \"\",\n \"---\",\n \"\",\n \"## Phase 3: Verify (`research:verify`)\",\n \"\",\n \"**Goal:** Reconcile every slice into a single verified deliverable.\",\n \"\",\n \"**Budget:** No new web searches. Read the scope, read every slice\",\n \"note, reconcile contradictions, write the deliverable and a short\",\n \"verification report.\",\n \"\",\n \"### Steps\",\n \"\",\n \"1. **Read the scope file** and every slice note listed in the issue\",\n \" body. If any slice file is missing, stop and re-open the\",\n \" corresponding slice issue with `status:needs-attention`.\",\n \"\",\n \"2. **Build a claim index.** For every assertion in any slice, note\",\n \" which slice(s) support it and which sources back it.\",\n \"\",\n \"3. **Reconcile contradictions.** When slices disagree:\",\n \" - Prefer the slice with stronger sources\",\n \" - Flag unresolved contradictions in the verification report\",\n \" - Do not silently pick a side\",\n \"\",\n \"4. **Write the deliverable** to\",\n \" `<DELIVERABLES_DIR>/<RESEARCH_SLUG>.md`. The structure is dictated\",\n \" by the acceptance criteria in the scope file. Every factual claim\",\n \" in the deliverable must cite at least one slice note.\",\n \"\",\n \"5. **Write a verification report** to\",\n \" `<DELIVERABLES_DIR>/<RESEARCH_SLUG>.verify.md`:\",\n \"\",\n \" ```markdown\",\n \" ---\",\n ' title: \"Verification Report: <question>\"',\n \" slug: <RESEARCH_SLUG>\",\n \" date: YYYY-MM-DD\",\n \" parent_issue: <N>\",\n \" slices_read: <count>\",\n \" ---\",\n \"\",\n \" # Verification Report: <question>\",\n \"\",\n \" ## Acceptance Criteria Coverage\",\n \" - [x] <criterion> — covered by slice(s) <NN, NN>\",\n \" - [ ] <criterion> — **not covered**; gap noted in deliverable\",\n \"\",\n \" ## Slice Coverage\",\n \" | Slice | Claims | Reused in deliverable | Notes |\",\n \" |-------|--------|-----------------------|-------|\",\n \" | 01 | <count> | <count> | |\",\n \"\",\n \" ## Reconciled Contradictions\",\n \" - <short summary of each reconciled contradiction and why>\",\n \"\",\n \" ## Unresolved Contradictions\",\n \" - <contradiction the verifier could not resolve>\",\n \"\",\n \" ## Gaps\",\n \" - <question the pipeline could not answer>\",\n \" ```\",\n \"\",\n \"6. **Comment on the scope issue** with a summary linking to the\",\n \" deliverable and verification report.\",\n \"\",\n \"7. **Commit and push.** Close the verify issue.\",\n \"\",\n \"---\",\n \"\",\n \"## Output Boundaries\",\n \"\",\n \"This agent writes **only** to:\",\n \"\",\n \"- `<SCOPE_DIR>/` — scope files (Phase 1)\",\n \"- `<SLICES_DIR>/` — slice notes (Phase 2)\",\n \"- `<DELIVERABLES_DIR>/` — deliverables and verification reports\",\n \" (Phase 3)\",\n \"\",\n \"The pipeline produces **notes and deliverables only**. It does not\",\n \"open downstream `type:requirement`, profile, or comparison issues —\",\n \"those are the responsibility of specialized downstream agents (e.g.\",\n \"`requirements-analyst`, `meeting-analyst`) that consume the\",\n \"deliverables produced here. Keep this boundary clean so the research\",\n \"pipeline stays generic.\",\n \"\",\n \"---\",\n \"\",\n \"## Rules\",\n \"\",\n \"- **One phase per session.** Never run two phases back-to-back in a\",\n \" single session.\",\n \"- **Persist before closing.** Every phase must write its output file\",\n \" before closing its issue.\",\n \"- **Do not expand scope mid-slice.** Overflow goes into the slice's\",\n \" overflow section and is flagged for verify — not into another\",\n \" slice's territory.\",\n \"- **Cite everything.** Claims without a source citation do not belong\",\n \" in a slice note or deliverable.\",\n \"- **Produce notes, not downstream work.** Do not create\",\n \" `type:requirement`, profile, or comparison issues from this\",\n \" pipeline. Emit deliverables under `<DELIVERABLES_DIR>/` and let\",\n \" downstream agents decide what to do with them.\",\n ].join(\"\\n\"),\n};\n\n/** Skill that kicks off a research pipeline cycle. */\nconst researchSkill: AgentSkill = {\n name: \"research\",\n description:\n \"Kick off a generic research micro-task pipeline. Creates a research:scope issue and dispatches Phase 1 (Scope) in the research-analyst agent.\",\n disableModelInvocation: true,\n userInvocable: true,\n context: \"fork\",\n agent: \"research-analyst\",\n platforms: { cursor: { exclude: true } },\n instructions: [\n \"# Research\",\n \"\",\n \"Kick off a generic research micro-task pipeline. Creates a\",\n \"`research:scope` issue carrying the research question and dispatches\",\n \"Phase 1 (Scope) in the research-analyst agent.\",\n \"\",\n \"## Usage\",\n \"\",\n \"/research <question>\",\n \"\",\n \"Optional extensions in the question body:\",\n \"- `sources: <list>` — authorized source categories or file paths\",\n \"- `slices: <N>` — override the default slice count (default 4, max 8)\",\n \"- `slug: <kebab-case>` — override the derived research slug\",\n \"- `acceptance: <list>` — explicit acceptance criteria for the\",\n \" deliverable\",\n \"\",\n \"## Default Paths\",\n \"\",\n \"If the project has no override in `docs/project-context.md` or\",\n \"`agentConfig.rules`, outputs land under:\",\n \"\",\n \"- `docs/research/scopes/<slug>.scope.md`\",\n \"- `docs/research/slices/<slug>-NN-<slice-slug>.slice.md`\",\n \"- `docs/research/deliverables/<slug>.md`\",\n \"- `docs/research/deliverables/<slug>.verify.md`\",\n \"\",\n \"## Steps\",\n \"\",\n \"1. Create a `research:scope` issue with `type:research`,\",\n \" `priority:medium`, and `status:ready`. Body must include the\",\n \" verbatim question, authorized sources, and any overrides.\",\n \"2. Execute Phase 1 (Scope) of the research-analyst agent.\",\n \"3. Phase 1 creates `research:slice` issues (one per slice) and a\",\n \" single `research:verify` issue. Each downstream issue declares\",\n \" its `Depends on:` predecessor.\",\n \"\",\n \"## Output\",\n \"\",\n \"- A scope file under the project's research scope directory\",\n \"- One slice note per slice under the slices directory\",\n \"- A single deliverable plus verification report under the deliverables\",\n \" directory\",\n \"- This pipeline produces **notes and deliverables only** — it does\",\n \" not open downstream `type:requirement` or profile issues.\",\n ].join(\"\\n\"),\n};\n\n/**\n * Research-pipeline bundle — enabled by default.\n *\n * Consuming projects can disable it with\n * `excludeBundles: [\"research-pipeline\"]`. `appliesWhen` always returns\n * `true` per this batch's directive that bundles assume peers are\n * present.\n *\n * Ships a sub-agent (`research-analyst`), a user-invocable skill\n * (`/research`), and `type:research` plus `research:*` phase labels.\n */\nexport const researchPipelineBundle: AgentRuleBundle = {\n name: \"research-pipeline\",\n description:\n \"Generic research micro-task pipeline: scope, N-way slice search/synthesize, and verify. Enabled by default; domain-neutral; filesystem-durable between phases.\",\n appliesWhen: () => true,\n rules: [\n {\n name: \"research-pipeline-workflow\",\n description:\n \"Describes the 3-phase generic research pipeline, the research:* label taxonomy, and the boundary against downstream specialized agents.\",\n scope: AGENT_RULE_SCOPE.ALWAYS,\n content: [\n \"# Research Pipeline Workflow\",\n \"\",\n \"Use `/research <question>` to kick off a generic research\",\n \"micro-task pipeline. The pipeline runs in 3 phases — scope, slice,\",\n \"verify — each tracked by its own GitHub issue labeled\",\n \"`research:scope`, `research:slice`, or `research:verify`. All\",\n \"issues carry `type:research`.\",\n \"\",\n \"The pipeline produces **notes and deliverables only**. It does\",\n \"not open downstream `type:requirement` or profile issues — those\",\n \"belong to specialized downstream agents that consume the\",\n \"deliverables.\",\n \"\",\n \"See the `research-analyst` agent definition for full workflow\",\n \"details, default paths, and phase-by-phase instructions.\",\n ].join(\"\\n\"),\n platforms: {\n cursor: { exclude: true },\n },\n tags: [\"workflow\"],\n },\n ],\n skills: [researchSkill],\n subAgents: [researchAnalystSubAgent],\n labels: [\n {\n name: \"type:research\",\n color: \"5319E7\",\n description:\n \"Work that produces or consumes a research note, slice, or deliverable\",\n },\n {\n name: \"research:scope\",\n color: \"C5DEF5\",\n description:\n \"Phase 1: decompose a research question into N focused slice issues\",\n },\n {\n name: \"research:slice\",\n color: \"BFDADC\",\n description:\n \"Phase 2: execute one research slice — search authorized sources and write a slice note\",\n },\n {\n name: \"research:verify\",\n color: \"D4C5F9\",\n description: \"Phase 3: reconcile slice notes into a verified deliverable\",\n },\n ],\n};\n","import { Component, Project } from \"projen\";\nimport { NodeProject } from \"projen/lib/javascript\";\nimport {\n ProjectMetadataOptions,\n ResolvedProjectMetadata,\n} from \"./project-metadata-options\";\n\n/**\n * Regex patterns for extracting owner and name from GitHub repository URLs.\n *\n * Matches:\n * - https://github.com/owner/repo\n * - https://github.com/owner/repo.git\n * - git@github.com:owner/repo.git\n * - git+https://github.com/owner/repo.git\n */\nconst GITHUB_HTTPS_RE =\n /(?:https?:\\/\\/|git\\+https:\\/\\/)github\\.com\\/([^/]+)\\/([^/.]+)(?:\\.git)?/;\nconst GITHUB_SSH_RE = /git@github\\.com:([^/]+)\\/([^/.]+)(?:\\.git)?/;\n\n/**\n * Extracts owner and name from a GitHub repository URL.\n * Returns undefined values if the URL does not match expected formats.\n */\nfunction parseGitHubUrl(url: string): {\n owner: string | undefined;\n name: string | undefined;\n} {\n const httpsMatch = url.match(GITHUB_HTTPS_RE);\n if (httpsMatch) {\n return { owner: httpsMatch[1], name: httpsMatch[2] };\n }\n\n const sshMatch = url.match(GITHUB_SSH_RE);\n if (sshMatch) {\n return { owner: sshMatch[1], name: sshMatch[2] };\n }\n\n return { owner: undefined, name: undefined };\n}\n\n/**\n * Provides structured project metadata consumed by AgentConfig, skills,\n * and other configulator features at synthesis time.\n *\n * This is a project-level component — it describes the project itself,\n * not any specific feature. It lives alongside MonorepoProject and\n * TypeScriptProject and is discovered by consumers via the static\n * `.of()` factory method.\n */\nexport class ProjectMetadata extends Component {\n /**\n * Returns the ProjectMetadata instance for a project. Walks up the parent\n * chain so sub-projects resolve the metadata declared on a root\n * `MonorepoProject` without needing a duplicate declaration of their own.\n * Returns `undefined` if no ancestor has a `ProjectMetadata` component.\n */\n public static of(project: Project): ProjectMetadata | undefined {\n const isProjectMetadata = (c: Component): c is ProjectMetadata =>\n c instanceof ProjectMetadata;\n let current: Project | undefined = project;\n while (current) {\n const found = current.components.find(isProjectMetadata);\n if (found) {\n return found;\n }\n current = current.parent;\n }\n return undefined;\n }\n\n /** Resolved metadata with auto-detected values filled in. */\n public readonly metadata: ResolvedProjectMetadata;\n\n constructor(project: Project, options: ProjectMetadataOptions = {}) {\n super(project);\n this.metadata = this.resolveMetadata(options);\n }\n\n /**\n * Merges explicit options with auto-detected values.\n * Auto-detection reads the repository URL from package.json\n * (via Projen's NodePackage manifest) and parses GitHub owner/name.\n * Explicit options always take precedence over auto-detected values.\n */\n private resolveMetadata(\n options: ProjectMetadataOptions,\n ): ResolvedProjectMetadata {\n const autoDetected = this.autoDetectRepository();\n\n return {\n repository: {\n owner: options.repository?.owner ?? autoDetected.owner,\n name: options.repository?.name ?? autoDetected.name,\n defaultBranch: options.repository?.defaultBranch ?? \"main\",\n },\n githubProject: options.githubProject,\n organization: options.organization,\n slack: options.slack,\n labels: options.labels,\n milestones: options.milestones,\n docsPath: options.docsPath,\n deployment: options.deployment,\n };\n }\n\n /**\n * Attempts to auto-detect repository owner and name from the Projen\n * project's package.json repository field.\n */\n private autoDetectRepository(): {\n owner: string | undefined;\n name: string | undefined;\n } {\n if (!(this.project instanceof NodeProject)) {\n return { owner: undefined, name: undefined };\n }\n\n const manifest = this.project.package.manifest;\n const repoField = manifest.repository;\n\n if (!repoField) {\n return { owner: undefined, name: undefined };\n }\n\n // repository can be a string URL or an object { type, url }\n const url =\n typeof repoField === \"string\" ? repoField : (repoField.url ?? \"\");\n\n return parseGitHubUrl(url);\n }\n}\n","import { Project } from \"projen/lib\";\nimport { ProjectMetadata } from \"../../projects/project-metadata\";\nimport { SlackMetadata } from \"../../projects/project-metadata-options\";\nimport { AgentRuleBundle } from \"../agent-config-options\";\nimport { AGENT_RULE_SCOPE } from \"../types\";\n\n/**\n * Returns true when the project's resolved metadata declares a Slack\n * integration. A declared integration means any of:\n *\n * - `slack.projectChannel` is set\n * - `slack.alertsChannel` is set\n * - `slack.channels` has at least one entry\n *\n * An empty `slack: {}` block is treated as \"not configured\" so consumers\n * do not accidentally activate the bundle by reserving the key.\n */\nfunction hasSlackConfig(slack: SlackMetadata | undefined): boolean {\n if (!slack) {\n return false;\n }\n if (slack.projectChannel || slack.alertsChannel) {\n return true;\n }\n if (slack.channels && Object.keys(slack.channels).length > 0) {\n return true;\n }\n return false;\n}\n\n/**\n * Slack bundle — auto-activated when the consuming project declares a\n * Slack integration via `ProjectMetadata.slack`. Consumers can still\n * opt in manually via `includeBundles: [\"slack\"]` when they have no\n * `ProjectMetadata` configured.\n *\n * Detection signal: any truthy value on\n * `ProjectMetadata.of(project).metadata.slack` that carries at least one\n * channel reference (`projectChannel`, `alertsChannel`, or a non-empty\n * `channels` record).\n */\nexport const slackBundle: AgentRuleBundle = {\n name: \"slack\",\n description:\n \"Slack MCP message formatting and best practices. Auto-activates when ProjectMetadata declares a Slack integration; can still be force-included via `includeBundles: ['slack']`.\",\n appliesWhen: (project: Project) => {\n const pm = ProjectMetadata.of(project);\n return hasSlackConfig(pm?.metadata.slack);\n },\n rules: [\n {\n name: \"slack-message-formatting\",\n description:\n \"Format Slack messages with explicit links so bullets and labels render correctly\",\n scope: AGENT_RULE_SCOPE.ALWAYS,\n content: [\n \"# Slack Message Formatting\",\n \"\",\n \"When composing or sending messages to Slack (e.g., via Slack MCP tools like `slack_send_message`), use formatting that Slack's mrkdwn parser renders correctly.\",\n \"\",\n \"## Rules\",\n \"\",\n \"1. **Use Slack's explicit link syntax** for any link in a message:\",\n \" - Format: `<https://example.com|display text>`\",\n \" - Text outside the angle brackets (bullets, labels) stays separate and won't merge into the link\",\n \"\",\n \"2. **Do not rely on auto-linkification** when the message has bullets or labels before URLs — auto-linked URLs can break or merge with surrounding text\",\n \"\",\n \"3. **Put each list item on its own line** with a newline between items so list structure is clear\",\n \"\",\n \"4. **Example — preferred:**\",\n \" ```\",\n \" Status update:\",\n \"\",\n \" • Feature A: <https://github.com/org/repo/pull/1|repo#1>\",\n \" • Feature B: <https://github.com/org/repo/pull/2|repo#2>\",\n \" ```\",\n \"\",\n \"5. **Avoid:** Plain URLs immediately after a bullet/label on the same line (e.g., `• Feature A: https://github.com/...`) when sending via API, as it can render with bullets inside or between links\",\n \"\",\n \"## Activation\",\n \"\",\n \"This bundle auto-activates when the consuming project declares a Slack integration through `ProjectMetadata` (any of `slack.projectChannel`, `slack.alertsChannel`, or a non-empty `slack.channels` record). If no `ProjectMetadata` is configured, opt in manually via `AgentConfigOptions.includeBundles: ['slack']`.\",\n ].join(\"\\n\"),\n tags: [\"workflow\"],\n },\n ],\n};\n","import { AgentRuleBundle } from \"../agent-config-options\";\nimport { PROJECT_CONTEXT_READER_SECTION } from \"./project-context\";\nimport {\n AGENT_MODEL,\n AGENT_RULE_SCOPE,\n AgentSkill,\n AgentSubAgent,\n} from \"../types\";\n\n/**\n * Sub-agent that researches and profiles software products into\n * structured markdown. Produces one profile per product, extracts a\n * feature matrix across a set of products, and ranks features using\n * configurable segment-importance weights.\n *\n * The prompt deliberately avoids hardcoded domains, companies, or source\n * projects. Consumers configure the product list, feature taxonomy,\n * segment weights, output paths, and downstream trigger behavior via the\n * skill invocation and by extending the rule in their own\n * `agentConfig.rules`.\n */\nconst softwareProfileAnalystSubAgent: AgentSubAgent = {\n name: \"software-profile-analyst\",\n description:\n \"Researches a software product (competitor, adjacent, incumbent, enabler, infrastructure, or ecosystem-tool) from public sources, produces a structured markdown profile, and contributes rows to a shared feature matrix ranked against configurable segment-importance weights. One product per session, tracked by software:* GitHub issue labels.\",\n model: AGENT_MODEL.POWERFUL,\n maxTurns: 80,\n platforms: { cursor: { exclude: true } },\n prompt: [\n \"# Software Profile Analyst Agent\",\n \"\",\n \"You research a single software product from public sources and write\",\n \"a structured markdown profile. Each profile cycle runs across a small\",\n \"sequence of GitHub issues — one per phase — and produces a single\",\n \"profile file on disk, a set of feature-matrix rows, and optional\",\n \"follow-up research issues for adjacent products.\",\n \"\",\n \"This agent is **domain-neutral**. It makes no assumptions about what\",\n \"the consuming project sells, which industry it serves, or which\",\n \"products matter to it. All domain-specific vocabulary, segment\",\n \"weights, feature taxonomies, output locations, and profile-template\",\n \"overrides come from the invoking issue body or the consuming\",\n \"project's configuration.\",\n \"\",\n \"Follow your project's shared agent conventions (`AGENTS.md`,\",\n \"`CLAUDE.md`, or equivalent) for all commit, branch, and PR rules.\",\n \"\",\n \"---\",\n \"\",\n ...PROJECT_CONTEXT_READER_SECTION,\n \"## Design Principles\",\n \"\",\n \"1. **One product per session.** Never profile two products in a\",\n \" single session, even if they came up together.\",\n \"2. **Public sources only.** Use the product's own site, docs, pricing\",\n \" pages, changelogs, public demos, and similar public material. Do\",\n \" not attempt to access gated or paywalled content unless the\",\n \" invoking issue body explicitly authorizes it.\",\n \"3. **Filesystem durability.** The profile file and feature-matrix\",\n \" rows are the deliverables. Both are committed to disk before the\",\n \" profile issue closes. Downstream phases read from disk — never\",\n \" rely on session memory.\",\n \"4. **Generic over specific.** No hardcoded product types, feature\",\n \" taxonomies, or segment assumptions. Use the generic software-type\",\n \" taxonomy below and let consuming projects override it via their\",\n \" `docs/project-context.md` or `agentConfig.rules`.\",\n \"5. **Cite everything.** Every non-trivial factual claim in the\",\n \" profile must carry a source citation (URL plus access date).\",\n \"6. **Follow-up, don't widen scope.** If the session turns up adjacent\",\n \" products worth evaluating, emit a follow-up issue rather than\",\n \" expanding the profile beyond its scope.\",\n \"7. **Segment weights live in project context.** Segment-importance\",\n \" weights belong in `docs/project-context.md` (or an override\",\n \" passed in the issue body). This agent reads them; it never\",\n \" invents them.\",\n \"\",\n \"---\",\n \"\",\n \"## Software Type Taxonomy\",\n \"\",\n \"Pick exactly one type per software profile. The taxonomy is\",\n \"deliberately generic — consuming projects override it via\",\n \"`agentConfig.rules` if they need a domain-specific refinement.\",\n \"\",\n \"| Type | Use for |\",\n \"|------|---------|\",\n \"| `competitor` | Products that offer a substitutable feature set to the same buyers for the same jobs-to-be-done. |\",\n \"| `adjacent` | Products that solve a neighboring problem or serve an overlapping buyer — not a direct substitute but worth understanding for positioning and integration. |\",\n \"| `incumbent` | Established, widely-deployed products that define the status quo in the space. Often older, broader, and harder to displace. |\",\n \"| `enabler` | Products the consuming project might build on, integrate with, or resell. Platforms, SDKs, APIs, and similar building blocks. |\",\n \"| `infrastructure` | Lower-level infrastructure or runtime components the consuming project depends on (databases, queues, identity, observability, etc.). |\",\n \"| `ecosystem-tool` | Developer tooling, plugins, extensions, or companion products that surround an incumbent or competitor without being one themselves. |\",\n \"\",\n \"If the product plausibly fits two types, prefer the one that reflects\",\n \"the **reason the profile was requested**, and note the secondary\",\n \"type in the profile body.\",\n \"\",\n \"---\",\n \"\",\n \"## Segment-Importance Weights\",\n \"\",\n \"Feature ranking uses **segment-importance weights** — a small table\",\n \"that assigns a numeric weight to each customer segment the consuming\",\n \"project cares about. Higher weight means the segment matters more to\",\n \"the project's own strategy; features that serve high-weight segments\",\n \"rank higher in the matrix.\",\n \"\",\n \"**Convention:** segment weights live in `docs/project-context.md`\",\n \"under a `## Segment Weights` section. The format is a simple\",\n \"markdown table with `segment` and `weight` columns. Weights are\",\n \"non-negative numbers; the scale is project-defined (0–1, 0–10, and\",\n \"0–100 are all valid as long as the project is internally\",\n \"consistent).\",\n \"\",\n \"Example `docs/project-context.md` fragment:\",\n \"\",\n \"```markdown\",\n \"## Segment Weights\",\n \"\",\n \"| segment | weight |\",\n \"|---------|--------|\",\n \"| enterprise | 3 |\",\n \"| mid-market | 2 |\",\n \"| smb | 1 |\",\n \"| hobbyist | 0.5 |\",\n \"```\",\n \"\",\n \"If `docs/project-context.md` does not define segment weights,\",\n \"**do not invent them**. Either:\",\n \"\",\n \"- Accept an `weights:` override in the invoking issue body, or\",\n \"- Produce the feature matrix with a single segment (`default`)\",\n \" weighted `1` and flag the missing weights in the profile's\",\n \" `## Open Questions` section.\",\n \"\",\n \"---\",\n \"\",\n \"## State Machine Overview\",\n \"\",\n \"```\",\n \"┌──────────────┐ ┌──────────────┐ ┌──────────────┐ ┌──────────────┐\",\n \"│ 1. RESEARCH │──▶│ 2. PROFILE │──▶│ 3. MATRIX │──▶│ 4. FOLLOWUP │\",\n \"│ Collect │ │ Write the │ │ Extract │ │ Enqueue │\",\n \"│ public │ │ structured │ │ feature rows │ │ research for │\",\n \"│ sources into │ │ markdown │ │ and score │ │ adjacent │\",\n \"│ bounded │ │ profile to │ │ against the │ │ products │\",\n \"│ notes file │ │ <PROFILES>/ │ │ weights │ │ surfaced │\",\n \"└──────────────┘ └──────────────┘ └──────────────┘ └──────────────┘\",\n \"```\",\n \"\",\n \"**Issue labels encode the phase:**\",\n \"\",\n \"| Label | Phase | Session work |\",\n \"|-------|-------|-------------|\",\n \"| `software:research` | 1. Research | Gather public sources. Write a bounded research-notes file. Create the profile issue. |\",\n \"| `software:profile` | 2. Profile | Read the research notes. Write the structured profile to `<PROFILES_DIR>`. Create the matrix issue. |\",\n \"| `software:matrix` | 3. Matrix | Read the profile. Extract feature rows into `<MATRIX_FILE>`. Score against segment weights. Create the follow-up issue if warranted. |\",\n \"| `software:followup` | 4. Followup | Read the profile. Enqueue software-research issues for adjacent products surfaced in the profile. |\",\n \"\",\n \"All issues also carry `type:software-profile` and a `status:*` label.\",\n \"\",\n \"**Issue count per product cycle:** 1 research + 1 profile + 1 matrix +\",\n \"0–1 followup = **3–4 sessions**. The followup phase is skipped when\",\n \"the profile did not surface any adjacent product worth researching.\",\n \"\",\n \"**Shortened paths:**\",\n \"- Research phase determines the product is out of scope (not\",\n \" relevant, insufficient public material) → research issue closes\",\n \" with a justification and no downstream issues are created → **1 session**.\",\n \"- Narrow product with no adjacent candidates → **3 sessions**.\",\n \"\",\n \"---\",\n \"\",\n \"## Configurable Paths\",\n \"\",\n \"The pipeline uses these placeholders. Consuming projects override the\",\n \"defaults by passing paths in the `/profile-software` skill invocation\",\n \"or by extending this rule in their own `agentConfig.rules`.\",\n \"\",\n \"| Placeholder | Meaning | Default |\",\n \"|-------------|---------|---------|\",\n \"| `<SOFTWARE_ROOT>` | Root folder for software profiles | `docs/software/` |\",\n \"| `<PROFILES_DIR>` | Final software profile files | `<SOFTWARE_ROOT>/profiles/` |\",\n \"| `<NOTES_DIR>` | Research-notes files from Phase 1 | `<SOFTWARE_ROOT>/notes/` |\",\n \"| `<MATRIX_FILE>` | Shared feature-matrix file | `<SOFTWARE_ROOT>/feature-matrix.md` |\",\n \"| `<PRODUCT_SLUG>` | Short kebab-case slug identifying the product | derived from the product name |\",\n \"\",\n \"If `docs/project-context.md` specifies a different software-research\",\n \"tree (for example by reusing the research-pipeline deliverables\",\n \"folder), prefer that. Otherwise fall back to the defaults above.\",\n \"\",\n \"---\",\n \"\",\n \"## Agent Loop\",\n \"\",\n \"Run this loop exactly once per session. Never start a second issue.\",\n \"\",\n \"1. Claim one open `type:software-profile` issue using phase priority:\",\n \" `software:research` > `software:profile` > `software:matrix` >\",\n \" `software:followup`.\",\n \"2. Transition `status:ready` → `status:in-progress` and create the\",\n \" branch per your project's branch-naming convention.\",\n \"3. Execute the phase handler that matches the issue's `software:*`\",\n \" label.\",\n \"4. Commit, push, open a PR (if applicable), and close the issue per\",\n \" your project's PR workflow.\",\n \"\",\n \"---\",\n \"\",\n \"## Phase 1: Research (`software:research`)\",\n \"\",\n \"**Goal:** Gather public sources into a bounded research-notes file.\",\n \"\",\n \"**Budget:** Public web search only, unless the issue body authorizes\",\n \"additional sources. Write one notes file. Do not write the profile\",\n \"or extend the feature matrix in this phase.\",\n \"\",\n \"### Steps\",\n \"\",\n \"1. **Read the issue body.** It should include:\",\n \" - The product name and website (if known)\",\n \" - The requested software type from the taxonomy above\",\n \" - The reason the profile was requested (framing — what does the\",\n \" invoking project want to learn?)\",\n \" - Optional: `<PRODUCT_SLUG>` override, custom output paths,\",\n \" `weights:` override for segment-importance weights\",\n \"\",\n \"2. **Derive `<PRODUCT_SLUG>`** if not supplied — a 2–4 word\",\n \" kebab-case summary of the product name. Ensure the slug is not\",\n \" already in use under `<PROFILES_DIR>/` or `<NOTES_DIR>/`.\",\n \"\",\n \"3. **Gather sources.** Prioritize in this order:\",\n \" - The product's own website (home, product, pricing, docs,\",\n \" changelog, integrations)\",\n \" - Public documentation, developer references, API docs\",\n \" - Public changelogs, release notes, roadmap posts\",\n \" - Reputable independent reviews and comparison articles\",\n \" - Public issue trackers or community forums when the issue body\",\n \" authorizes them\",\n \"\",\n \"4. **Write a research-notes file** to\",\n \" `<NOTES_DIR>/<PRODUCT_SLUG>.notes.md`:\",\n \"\",\n \" ```markdown\",\n \" ---\",\n ' title: \"Research Notes: <product name>\"',\n \" slug: <PRODUCT_SLUG>\",\n \" software_type: <one of the taxonomy values>\",\n \" date: YYYY-MM-DD\",\n \" parent_issue: <N>\",\n \" ---\",\n \"\",\n \" # Research Notes: <product name>\",\n \"\",\n \" ## Framing\",\n \" <why this product was requested and what to learn>\",\n \"\",\n \" ## Raw Findings\",\n \" - <finding> — source: <citation>\",\n \"\",\n \" ## Candidate Features\",\n \" - <feature name>: <one-line description> — source: <citation>\",\n \"\",\n \" ## Candidate Adjacent Products\",\n \" - <product name> — source: <citation>\",\n \"\",\n \" ## Open Questions\",\n \" <anything the notes could not answer from public sources>\",\n \"\",\n \" ## Sources\",\n \" - <source URL or file path> — <date accessed>\",\n \" ```\",\n \"\",\n \"5. **Create the `software:profile` issue** with\",\n \" `Depends on: #<research-issue>`. Its body references the notes\",\n \" file path and the requested software type.\",\n \"\",\n \"6. **Commit and push** the notes file. Close the research issue.\",\n \"\",\n \"---\",\n \"\",\n \"## Phase 2: Profile (`software:profile`)\",\n \"\",\n \"**Goal:** Write the structured software profile from the research\",\n \"notes.\",\n \"\",\n \"**Budget:** No new web searches unless explicitly needed to fill a\",\n \"gap the notes flagged. Write one profile file.\",\n \"\",\n \"### Steps\",\n \"\",\n \"1. **Read the research-notes file** referenced in the issue body.\",\n \"\",\n \"2. **Check for duplicates.** If `<PROFILES_DIR>/<PRODUCT_SLUG>.md`\",\n \" already exists, open it and decide whether to update in place or\",\n \" flag a naming collision. Never silently overwrite a non-trivial\",\n \" existing profile.\",\n \"\",\n \"3. **Write the profile** to `<PROFILES_DIR>/<PRODUCT_SLUG>.md` using\",\n \" the template below. All sections are required; use\",\n \" `_Not available in public sources._` when a section cannot be\",\n \" filled from the notes.\",\n \"\",\n \" ```markdown\",\n \" ---\",\n ' title: \"<product name>\"',\n \" slug: <PRODUCT_SLUG>\",\n \" software_type: <one of the taxonomy values>\",\n \" website: <primary URL>\",\n \" date: YYYY-MM-DD\",\n \" parent_issue: <N>\",\n \" notes: <NOTES_DIR>/<PRODUCT_SLUG>.notes.md\",\n \" ---\",\n \"\",\n \" # <product name>\",\n \"\",\n \" ## Summary\",\n \" <2–4 sentence elevator description: what it does, who it's for>\",\n \"\",\n \" ## Classification\",\n \" - **Primary type:** <taxonomy value>\",\n \" - **Secondary type (if any):** <taxonomy value or `n/a`>\",\n \" - **Relevance to this project:** <1–2 sentences tying the product\",\n \" back to the framing from the notes>\",\n \"\",\n \" ## Offering\",\n \" - **Jobs-to-be-done:** <bullet list of core use cases>\",\n \" - **Target segments:** <who this product is for; reuse segment\",\n \" names from the project's segment-weights table when possible>\",\n \" - **Pricing model:** <if disclosed>\",\n \" - **Deployment model:** <SaaS / self-hosted / hybrid / on-prem>\",\n \"\",\n \" ## Features\",\n \" <grouped bullet list of notable features, each cited. These become\",\n \" the rows in the feature matrix during Phase 3.>\",\n \"\",\n \" ## Technology Signals\",\n \" <stack hints from docs, integrations, and public engineering\",\n \" content — each bullet cited>\",\n \"\",\n \" ## Positioning / Differentiation\",\n \" <how the product describes itself and how it differs from adjacent\",\n \" products — use its own language, cited, rather than inferred>\",\n \"\",\n \" ## Risks / Open Questions\",\n \" <what the profile could not answer; flag anything the matrix or\",\n \" follow-up phase should escalate>\",\n \"\",\n \" ## Follow-up Candidates\",\n \" - **Adjacent products to evaluate:** <list of candidate product\",\n \" names>\",\n \"\",\n \" ## Sources\",\n \" - <source URL> — <date accessed>\",\n \" ```\",\n \"\",\n \"4. **Create the `software:matrix` issue** with\",\n \" `Depends on: #<profile-issue>`. Its body references the profile\",\n \" path, the matrix file path, and the segment-weights source\",\n \" (`docs/project-context.md` or an explicit override).\",\n \"\",\n \"5. **Commit and push** the profile file. Close the profile issue.\",\n \"\",\n \"---\",\n \"\",\n \"## Phase 3: Matrix (`software:matrix`)\",\n \"\",\n \"**Goal:** Extract feature rows from the profile into the shared\",\n \"feature matrix and score each feature against the segment-importance\",\n \"weights.\",\n \"\",\n \"**Budget:** No new research. Read the profile, update the matrix,\",\n \"close the phase.\",\n \"\",\n \"### Matrix File Format\",\n \"\",\n \"The feature matrix is a single markdown file at `<MATRIX_FILE>`. It\",\n \"uses a wide table with one row per (product, feature) pair and one\",\n \"column per segment plus a computed `score` column.\",\n \"\",\n \"```markdown\",\n \"---\",\n 'title: \"Software Feature Matrix\"',\n \"weights_source: docs/project-context.md#segment-weights\",\n \"updated: YYYY-MM-DD\",\n \"---\",\n \"\",\n \"# Software Feature Matrix\",\n \"\",\n \"| product | feature | <segment-1> | <segment-2> | ... | score | source |\",\n \"|---------|---------|-------------|-------------|-----|-------|--------|\",\n \"| <slug> | <feature-name> | 0–1 | 0–1 | ... | <weighted-sum> | <profile-path> |\",\n \"```\",\n \"\",\n \"Segment columns carry a **coverage score** in `[0, 1]` representing\",\n \"how well the feature serves that segment — `1` means fully covered,\",\n \"`0` means not covered, intermediate values reflect partial coverage\",\n \"(e.g. self-serve only, gated by pricing tier, limited by scale).\",\n \"\",\n \"The `score` column is the weighted sum:\",\n \"\",\n \"```\",\n \"score = Σ (coverage[segment] * weight[segment])\",\n \"```\",\n \"\",\n \"using the weights loaded from `docs/project-context.md`.\",\n \"\",\n \"### Steps\",\n \"\",\n \"1. **Load segment weights.** Read `## Segment Weights` from\",\n \" `docs/project-context.md`. If absent, fall back to the\",\n \" `weights:` override in the issue body, or the single-segment\",\n \" default described in `## Segment-Importance Weights` above.\",\n \"\",\n \"2. **Read the profile file** referenced in the issue body. Extract\",\n \" the bullets under `## Features` as candidate matrix rows.\",\n \"\",\n \"3. **Open or create `<MATRIX_FILE>`.** If the file does not exist,\",\n \" write the front-matter and header row using the current set of\",\n \" segment columns. If it exists, ensure its segment columns match\",\n \" the loaded weights; if they have drifted, add any missing columns\",\n \" and leave a note in the profile's `## Risks / Open Questions`.\",\n \"\",\n \"4. **Append or update rows** for the current product. One row per\",\n \" feature. For each row:\",\n \" - Assign a coverage score in `[0, 1]` for each segment, citing\",\n \" the profile section that justifies the score.\",\n \" - Compute the `score` as the weighted sum.\",\n \" - Set the `source` column to the profile file path.\",\n \"\",\n \"5. **Update the matrix front-matter** (`updated: YYYY-MM-DD`).\",\n \"\",\n \"6. **Decide whether a follow-up issue is warranted.** Create a\",\n \" `software:followup` issue (depending on this matrix issue) only\",\n \" if the profile lists at least one adjacent product candidate.\",\n \" Otherwise, note in the matrix issue's closing comment that no\",\n \" follow-up is needed.\",\n \"\",\n \"7. **Commit and push** the matrix file (and any profile updates).\",\n \" Close the matrix issue.\",\n \"\",\n \"---\",\n \"\",\n \"## Phase 4: Followup (`software:followup`)\",\n \"\",\n \"**Goal:** Create downstream research issues for the adjacent products\",\n \"surfaced in the profile.\",\n \"\",\n \"**Budget:** No new research. Read the profile, enqueue issues, close\",\n \"the phase.\",\n \"\",\n \"### Steps\",\n \"\",\n \"1. **Read the profile file** referenced in the issue body.\",\n \"\",\n \"2. **Enqueue software-research issues** for each entry under\",\n \" `Follow-up Candidates > Adjacent products to evaluate`. Each new\",\n \" issue follows the same 4-phase pipeline — start it in the\",\n \" `software:research` phase with `type:software-profile`,\",\n \" `priority:medium`, and `status:ready`.\",\n \"\",\n \"3. **Cross-link** — update the profile's `## Follow-up Candidates`\",\n \" section so each entry references its newly-created issue number.\",\n \"\",\n \"4. **Commit and push** (if the profile was updated). Close the\",\n \" followup issue.\",\n \"\",\n \"---\",\n \"\",\n \"## Output Boundaries\",\n \"\",\n \"This agent writes **only** to:\",\n \"\",\n \"- `<NOTES_DIR>/` — research-notes files (Phase 1)\",\n \"- `<PROFILES_DIR>/` — software profiles (Phase 2, updated in later\",\n \" phases)\",\n \"- `<MATRIX_FILE>` — shared feature matrix (Phase 3)\",\n \"\",\n \"The pipeline produces **profiles, notes, and matrix rows only**.\",\n \"Deeper research on adjacent products is delegated to new cycles of\",\n \"this same pipeline via follow-up issues. This agent never writes\",\n \"company profiles, person profiles, formal requirement documents, or\",\n \"comparative long-form analyses itself. Keep this boundary clean so\",\n \"the software-profile pipeline stays generic.\",\n \"\",\n \"---\",\n \"\",\n \"## Rules\",\n \"\",\n \"- **One product per session.** Never profile two products back-to-back.\",\n \"- **Persist before closing.** Every phase must write its output file\",\n \" before closing its issue.\",\n \"- **Cite everything.** Profile claims without source citations do not\",\n \" belong in the deliverable.\",\n \"- **No invented weights.** Segment weights come from\",\n \" `docs/project-context.md` or an explicit issue-body override. If\",\n \" neither is available, fall back to the single-segment default and\",\n \" flag the gap — never guess.\",\n \"- **Produce profiles and matrix rows, not downstream work.** Do not\",\n \" open `type:requirement` or formal evaluation issues from this\",\n \" pipeline. Follow-up work is scoped through `software:followup` or\",\n \" delegated to downstream research agents.\",\n ].join(\"\\n\"),\n};\n\n/** Skill that kicks off a software profile cycle. */\nconst profileSoftwareSkill: AgentSkill = {\n name: \"profile-software\",\n description:\n \"Kick off a software-profile pipeline. Creates a software:research issue for the given product and dispatches Phase 1 (Research) in the software-profile-analyst agent.\",\n disableModelInvocation: true,\n userInvocable: true,\n context: \"fork\",\n agent: \"software-profile-analyst\",\n platforms: { cursor: { exclude: true } },\n instructions: [\n \"# Profile Software\",\n \"\",\n \"Kick off a software-profile pipeline. Creates a `software:research`\",\n \"issue carrying the product name, type, and framing, then dispatches\",\n \"Phase 1 (Research) in the software-profile-analyst agent.\",\n \"\",\n \"## Usage\",\n \"\",\n \"/profile-software <product-name>\",\n \"\",\n \"Optional extensions in the issue body:\",\n \"- `type: <competitor | adjacent | incumbent | enabler |\",\n \" infrastructure | ecosystem-tool>` — override the default type\",\n \" inference\",\n \"- `website: <url>` — canonical website if not obvious from the name\",\n \"- `framing: <text>` — why this profile was requested and what to learn\",\n \"- `slug: <kebab-case>` — override the derived product slug\",\n \"- `weights: <table>` — override the segment-importance weights for\",\n \" this profile cycle (otherwise loaded from\",\n \" `docs/project-context.md`)\",\n \"- `sources: <list>` — additional authorized sources beyond public web\",\n \"\",\n \"## Default Paths\",\n \"\",\n \"If the project has no override in `docs/project-context.md` or\",\n \"`agentConfig.rules`, outputs land under:\",\n \"\",\n \"- `docs/software/notes/<slug>.notes.md`\",\n \"- `docs/software/profiles/<slug>.md`\",\n \"- `docs/software/feature-matrix.md` (shared across all products)\",\n \"\",\n \"## Steps\",\n \"\",\n \"1. Create a `software:research` issue with `type:software-profile`,\",\n \" `priority:medium`, and `status:ready`. Body must include the\",\n \" product name, selected type, framing, and any overrides.\",\n \"2. Execute Phase 1 (Research) of the software-profile-analyst\",\n \" agent.\",\n \"3. Phase 1 creates the `software:profile` issue. Phase 2 creates\",\n \" the `software:matrix` issue. Phase 3 may create a\",\n \" `software:followup` issue. Each downstream issue declares its\",\n \" `Depends on:` predecessor.\",\n \"\",\n \"## Output\",\n \"\",\n \"- A research-notes file under the project's notes directory\",\n \"- A single software profile under the profiles directory\",\n \"- One or more rows appended to the shared feature-matrix file,\",\n \" scored against the configured segment weights\",\n \"- Optional follow-up research issues for adjacent products\",\n \" surfaced in the profile\",\n \"- This pipeline produces **profiles, notes, and matrix rows only**\",\n \" — it does not write company profiles, person profiles, or formal\",\n \" requirement documents itself.\",\n ].join(\"\\n\"),\n};\n\n/**\n * Software-profile bundle — enabled by default.\n *\n * Consuming projects can disable it with\n * `excludeBundles: [\"software-profile\"]`. `appliesWhen` always returns\n * `true` per this batch's directive that bundles assume peers are\n * present.\n *\n * Ships a sub-agent (`software-profile-analyst`), a user-invocable skill\n * (`/profile-software`), and `type:software-profile` plus `software:*`\n * phase labels.\n */\nexport const softwareProfileBundle: AgentRuleBundle = {\n name: \"software-profile\",\n description:\n \"Software research, profiling, and feature-matrix pipeline: research, profile, matrix, followup. Enabled by default; domain-neutral; filesystem-durable between phases; ranks features against configurable segment-importance weights.\",\n appliesWhen: () => true,\n rules: [\n {\n name: \"software-profile-workflow\",\n description:\n \"Describes the 4-phase software-profile pipeline, the software:* label taxonomy, the generic software-type taxonomy, and the segment-weights convention that drives feature-matrix scoring.\",\n scope: AGENT_RULE_SCOPE.ALWAYS,\n content: [\n \"# Software Profile Workflow\",\n \"\",\n \"Use `/profile-software <product-name>` to kick off a software\",\n \"research, profiling, and feature-matrix pipeline. The pipeline\",\n \"runs in up to 4 phases — research, profile, matrix, followup —\",\n \"each tracked by its own GitHub issue labeled\",\n \"`software:research`, `software:profile`, `software:matrix`, or\",\n \"`software:followup`. All issues carry `type:software-profile`.\",\n \"\",\n \"The pipeline produces **software profiles, research notes, and\",\n \"rows in a shared feature matrix**. Features are ranked against\",\n \"segment-importance weights declared in\",\n \"`docs/project-context.md` under a `## Segment Weights` section.\",\n \"Deeper research on adjacent products surfaced in a profile is\",\n \"delegated to new cycles of this same pipeline via\",\n \"`software:followup` issues.\",\n \"\",\n \"See the `software-profile-analyst` agent definition for full\",\n \"workflow details, default paths, the software-type taxonomy,\",\n \"the segment-weights convention, and phase-by-phase\",\n \"instructions.\",\n ].join(\"\\n\"),\n platforms: {\n cursor: { exclude: true },\n },\n tags: [\"workflow\"],\n },\n ],\n skills: [profileSoftwareSkill],\n subAgents: [softwareProfileAnalystSubAgent],\n labels: [\n {\n name: \"type:software-profile\",\n color: \"0E8A16\",\n description:\n \"Work that produces or maintains a software profile, research notes, or feature-matrix rows\",\n },\n {\n name: \"software:research\",\n color: \"C5DEF5\",\n description:\n \"Phase 1: gather public sources about a software product into a research-notes file\",\n },\n {\n name: \"software:profile\",\n color: \"BFDADC\",\n description:\n \"Phase 2: write the structured software profile from research notes\",\n },\n {\n name: \"software:matrix\",\n color: \"D4C5F9\",\n description:\n \"Phase 3: extract feature rows into the shared feature matrix and score them against segment weights\",\n },\n {\n name: \"software:followup\",\n color: \"FBCA04\",\n description:\n \"Phase 4: enqueue follow-up research issues for adjacent products surfaced in the profile\",\n },\n ],\n};\n","import { Component, FileBase, JsonFile, Project, Task } from \"projen/lib\";\nimport { BuildWorkflowOptions } from \"projen/lib/build\";\nimport { JobPermission } from \"projen/lib/github/workflows-model\";\nimport { NodeProject } from \"projen/lib/javascript\";\nimport { TurboRepoTask } from \"./turbo-repo-task\";\n\n/*******************************************************************************\n *\n * Turbo Repo Config\n *\n ******************************************************************************/\n\nexport const ROOT_TURBO_TASK_NAME = \"turbo:build\";\nexport const ROOT_CI_TASK_NAME = \"build:all\";\n\nexport interface RemoteCacheOptions {\n /**\n * Local profile name to use when fetching the cache endpoint and token.\n */\n readonly profileName: string;\n\n /**\n * OIDC role to assume when fetching the cache endpoint and token.\n */\n readonly oidcRole: string;\n\n /**\n * Name for the params used to store the cache endpoint.\n */\n readonly endpointParamName: string;\n\n /**\n * Name for the params used to store the cache's API token.\n */\n readonly tokenParamName: string;\n\n /**\n * team name used in remote cache commands\n */\n readonly teamName: string;\n}\n\nexport interface TurboRepoOptions {\n /**\n * Version of turborepo to use.\n *\n * @default: specified in versions file\n */\n readonly turboVersion?: string;\n\n /**\n * Extend from the root turbo.json to create specific configuration for a package using Package Configurations.\n *\n * The only valid value for extends is [\"//\"] to inherit configuration from the root turbo.json.\n * If extends is used in the root turbo.json, it will be ignored.\n *\n * https://turbo.build/repo/docs/reference/configuration#extends\n */\n readonly extends?: Array<string>;\n\n /**\n * A list of globs that you want to include in all task hashes. If any file matching these globs changes, all tasks will miss cache. Globs are relative to the location of turbo.json.\n *\n * By default, all files in source control in the Workspace root are included in the global hash.\n *\n * Globs must be in the repository's source control root. Globs outside of the repository aren't supported.\n *\n * https://turbo.build/repo/docs/reference/configuration#globaldependencies\n */\n readonly globalDependencies?: Array<string>;\n\n /**\n * A list of environment variables that you want to impact the hash of all tasks. Any change to these environment variables will cause all tasks to miss cache.\n *\n * For more on wildcard and negation syntax, see the env section.\n *\n * https://turbo.build/repo/docs/reference/configuration#globalenv\n */\n readonly globalEnv?: Array<string>;\n\n /**\n * A list of environment variables that you want to make available to tasks.\n * Using this key opts all tasks into Strict\n * Environment Variable Mode.\n *\n * Additionally, Turborepo has a built-in set of global passthrough variables\n * for common cases, like operating system environment variables. This\n * includes variables like HOME, PATH, APPDATA, SHELL, PWD, and more. The full\n * list can be found in the source code.\n *\n * Passthrough values do not contribute to hashes for caching\n *\n * If you want changes in these variables to cause cache misses, you will need\n * to include them in env or globalEnv.\n *\n * https://turbo.build/repo/docs/reference/configuration#globalpassthroughenv\n */\n readonly globalPassThroughEnv?: Array<string>;\n\n /**\n * @default: \"stream\"\n *\n * Select a terminal UI for the repository.\n *\n * \"tui\" allows for viewing each log at once and interacting with the task.\n * \"stream\" outputs logs as they come in and is not interactive.\n *\n * https://turbo.build/repo/docs/reference/configuration#ui\n */\n readonly ui?: \"tui\" | \"stream\";\n\n /**\n * @default: false\n *\n * Turborepo uses your repository's lockfile to determine caching behavior,\n * Package Graphs, and more. Because of this, we use the packageManager field\n * to help you stabilize your Turborepo.\n *\n * To help with incremental migration or in situations where you can't use\n * the packageManager field, you may use\n * --dangerously-disable-package-manager-check to opt out of this check and\n * assume the risks of unstable lockfiles producing unpredictable behavior.\n * When disabled, Turborepo will attempt a best-effort discovery of the\n * intended package manager meant for the repository.\n *\n * https://turbo.build/repo/docs/reference/configuration#dangerouslydisablepackagemanagercheck\n */\n readonly dangerouslyDisablePackageManagerCheck?: boolean;\n\n /**\n * @default: \".turbo/cache\"\n *\n * Specify the filesystem cache directory.\n *\n * https://turbo.build/repo/docs/reference/configuration#cachedir\n */\n readonly cacheDir?: string;\n\n /**\n * @default: true\n *\n * Turborepo runs a background process to pre-calculate some expensive\n * operations. This standalone process (daemon) is a performance optimization,\n * and not required for proper functioning of turbo.\n *\n * https://turbo.build/repo/docs/reference/configuration#daemon\n */\n readonly daemon?: boolean;\n\n /**\n * @default: \"strict\"\n *\n * Turborepo's Environment Modes allow you to control which environment\n * variables are available to a task at runtime:\n *\n *\"strict\": Filter environment variables to only those that are specified\n * in the env and globalEnv keys in turbo.json.\n *\n * \"loose\": Allow all environment variables for the process to be available.\n *\n * https://turbo.build/repo/docs/reference/configuration#envmode\n */\n readonly envMode?: string;\n\n /*****************************************************************************\n *\n * Cache Settings\n *\n ****************************************************************************/\n\n /**\n * Cache settings, if using remote cache.\n */\n readonly remoteCacheOptions?: RemoteCacheOptions;\n\n /**\n * Env Args that will bre added to turbo's build:all task\n *\n * @default: {}\n */\n readonly buildAllTaskEnvVars?: Record<string, string>;\n\n /*****************************************************************************\n *\n * Tasks - Optionally define a different projen task for one of the lifecycle\n * steps.\n *\n ****************************************************************************/\n\n /**\n * Pre compile task\n *\n * @default: \"pre-compile\"\n */\n readonly preCompileTask?: Task;\n\n /**\n * Compile task\n *\n * @default: \"compile\"\n */\n readonly compileTask?: Task;\n\n /**\n * Post compile task\n *\n * @default: \"post-compile\"\n */\n readonly postCompileTask?: Task;\n\n /**\n * Test task\n *\n * @default: \"test\"\n */\n readonly testTask?: Task;\n\n /**\n * Package task\n *\n * @default: \"package\"\n */\n readonly packageTask?: Task;\n}\n\nexport class TurboRepo extends Component {\n /**\n * Static method to discovert turbo in a project.\n */\n public static of(project: Project): TurboRepo | undefined {\n const isDefined = (c: Component): c is TurboRepo => c instanceof TurboRepo;\n return project.components.find(isDefined);\n }\n\n public static buildWorkflowOptions = (\n remoteCacheOptions: RemoteCacheOptions,\n ): Partial<BuildWorkflowOptions> => {\n return {\n env: {\n GIT_BRANCH_NAME: \"${{ github.head_ref || github.ref_name }}\",\n },\n permissions: {\n contents: JobPermission.WRITE,\n idToken: JobPermission.WRITE,\n },\n preBuildSteps: [\n {\n name: \"AWS Creds for SSM\",\n uses: \"aws-actions/configure-aws-credentials@v4\",\n with: {\n [\"role-to-assume\"]: remoteCacheOptions.oidcRole,\n [\"aws-region\"]: \"us-east-1\",\n [\"role-duration-seconds\"]: \"900\",\n },\n },\n ],\n };\n };\n\n /**\n * Version of turborepo to use.\n */\n public readonly turboVersion: string;\n\n /**\n * Extend from the root turbo.json to create specific configuration for a package using Package Configurations.\n *\n * The only valid value for extends is [\"//\"] to inherit configuration from the root turbo.json.\n * If extends is used in the root turbo.json, it will be ignored.\n *\n * https://turbo.build/repo/docs/reference/configuration#extends\n */\n public readonly extends: Array<string>;\n\n /**\n * A list of globs that you want to include in all task hashes. If any file matching these globs changes, all tasks will miss cache. Globs are relative to the location of turbo.json.\n *\n * By default, all files in source control in the Workspace root are included in the global hash.\n *\n * Globs must be in the repository's source control root. Globs outside of the repository aren't supported.\n *\n * https://turbo.build/repo/docs/reference/configuration#globaldependencies\n */\n public readonly globalDependencies: Array<string>;\n\n /**\n * A list of environment variables that you want to impact the hash of all tasks. Any change to these environment variables will cause all tasks to miss cache.\n *\n * For more on wildcard and negation syntax, see the env section.\n *\n * https://turbo.build/repo/docs/reference/configuration#globalenv\n */\n public readonly globalEnv: Array<string>;\n\n /**\n * A list of environment variables that you want to make available to tasks.\n * Using this key opts all tasks into Strict\n * Environment Variable Mode.\n *\n * Additionally, Turborepo has a built-in set of global passthrough variables\n * for common cases, like operating system environment variables. This\n * includes variables like HOME, PATH, APPDATA, SHELL, PWD, and more. The full\n * list can be found in the source code.\n *\n * Passthrough values do not contribute to hashes for caching\n *\n * If you want changes in these variables to cause cache misses, you will need\n * to include them in env or globalEnv.\n *\n * https://turbo.build/repo/docs/reference/configuration#globalpassthroughenv\n */\n public readonly globalPassThroughEnv: Array<string>;\n\n /**\n * @default: \"stream\"\n *\n * Select a terminal UI for the repository.\n *\n * \"tui\" allows for viewing each log at once and interacting with the task.\n * \"stream\" outputs logs as they come in and is not interactive.\n *\n * https://turbo.build/repo/docs/reference/configuration#ui\n */\n public readonly ui: \"tui\" | \"stream\";\n\n /**\n * @default: false\n *\n * Turborepo uses your repository's lockfile to determine caching behavior,\n * Package Graphs, and more. Because of this, we use the packageManager field\n * to help you stabilize your Turborepo.\n *\n * To help with incremental migration or in situations where you can't use\n * the packageManager field, you may use\n * --dangerously-disable-package-manager-check to opt out of this check and\n * assume the risks of unstable lockfiles producing unpredictable behavior.\n * When disabled, Turborepo will attempt a best-effort discovery of the\n * intended package manager meant for the repository.\n *\n * https://turbo.build/repo/docs/reference/configuration#dangerouslydisablepackagemanagercheck\n */\n public readonly dangerouslyDisablePackageManagerCheck: boolean;\n\n /**\n * @default: \".turbo/cache\"\n *\n * Specify the filesystem cache directory.\n *\n * https://turbo.build/repo/docs/reference/configuration#cachedir\n */\n public readonly cacheDir: string;\n\n /**\n * @default: true\n *\n * Turborepo runs a background process to pre-calculate some expensive\n * operations. This standalone process (daemon) is a performance optimization,\n * and not required for proper functioning of turbo.\n *\n * https://turbo.build/repo/docs/reference/configuration#daemon\n */\n public readonly daemon: boolean;\n\n /**\n * @default: \"strict\"\n *\n * Turborepo's Environment Modes allow you to control which environment\n * variables are available to a task at runtime:\n *\n *\"strict\": Filter environment variables to only those that are specified\n * in the env and globalEnv keys in turbo.json.\n *\n * \"loose\": Allow all environment variables for the process to be available.\n *\n * https://turbo.build/repo/docs/reference/configuration#envmode\n */\n public readonly envMode: string;\n\n /*****************************************************************************\n *\n * Cache Settings\n *\n ****************************************************************************/\n\n /**\n * Cache settings, if using remote cache.\n */\n public readonly remoteCacheOptions?: RemoteCacheOptions;\n\n /**\n * is this the root project?\n */\n public readonly isRootProject: boolean;\n\n /**\n * Turbo's build:all task at the root of the monorepo.\n *\n * This is a normal projen task that runs the root turbo task.\n */\n public readonly buildAllTask?: Task;\n\n /**\n * Main turbo:build task\n *\n * This is a special Turbo task\n */\n public readonly buildTask: TurboRepoTask;\n\n /**\n * pre compile task\n */\n public readonly preCompileTask?: TurboRepoTask;\n\n /**\n * compile task\n */\n public readonly compileTask?: TurboRepoTask;\n\n /**\n * post compile task\n */\n public readonly postCompileTask?: TurboRepoTask;\n\n /**\n * Test task\n */\n public readonly testTask?: TurboRepoTask;\n\n /**\n * Package task\n */\n public readonly packageTask?: TurboRepoTask;\n\n /**\n * Sub-Tasks to run\n */\n public readonly tasks: Array<TurboRepoTask> = [];\n\n /**\n * Env Args that will bre added to turbo's build:all task\n */\n public readonly buildAllTaskEnvVars: Record<string, string>;\n\n constructor(\n public readonly project: NodeProject,\n options: TurboRepoOptions = {},\n ) {\n super(project);\n\n this.turboVersion = options.turboVersion ?? \"catalog:\";\n this.isRootProject = project === project.root;\n\n /**\n * Add turborepo package to root project.\n */\n if (this.isRootProject) {\n project.addDevDeps(`turbo@${this.turboVersion}`);\n }\n\n /**\n * Ignore the working cache for turbo.\n */\n project.gitignore.addPatterns(\"/.turbo\");\n project.npmignore?.addPatterns(\"/.turbo/\");\n\n /***************************************************************************\n *\n * Set some default options\n *\n **************************************************************************/\n\n this.extends = options.extends ?? (this.isRootProject ? [] : [\"//\"]);\n this.globalDependencies = options.globalDependencies ?? [];\n this.globalEnv = options.globalEnv ?? [];\n this.globalPassThroughEnv = options.globalPassThroughEnv ?? [];\n this.ui = options.ui ?? \"stream\";\n this.dangerouslyDisablePackageManagerCheck =\n options.dangerouslyDisablePackageManagerCheck ?? false;\n this.cacheDir = options.cacheDir ?? \".turbo/cache\";\n this.daemon = options.daemon ?? true;\n this.envMode = options.envMode ?? \"strict\";\n this.remoteCacheOptions = options.remoteCacheOptions;\n this.buildAllTaskEnvVars = options.buildAllTaskEnvVars ?? {};\n\n /***************************************************************************\n *\n * Turbo Build Task\n *\n * All turbo configs contain a turbo build task.\n *\n **************************************************************************/\n\n /**\n * For the root project, include all generated file paths as inputs so that\n * when projen regenerates files (e.g. turbo.json, workflows), the root task\n * cache is invalidated.\n */\n const rootGeneratedFiles = this.isRootProject\n ? this.project.components\n .filter((c): c is FileBase => c instanceof FileBase)\n .map((c) => c.path)\n : [];\n\n /**\n * The turbo entry point definition for the turbo:build task. This exists\n * in each project and is written tot he turbo.json file. This task is not\n * a projen task or a Node task.\n */\n this.buildTask = new TurboRepoTask(this.project, {\n name: ROOT_TURBO_TASK_NAME,\n dependsOn: this.isRootProject ? [`^${ROOT_TURBO_TASK_NAME}`] : [],\n ...(rootGeneratedFiles.length > 0 && { inputs: rootGeneratedFiles }),\n });\n\n /***************************************************************************\n *\n * Turbo Build All Task\n *\n * The Projen entry point. This only exists in the root and is a projen\n * task that can be run using pnpm.\n *\n * - Turns off telemetry\n * - Runs root turbo task to build all sub-projects.\n *\n **************************************************************************/\n\n if (this.isRootProject) {\n /**\n * Create and configure the build all task.\n */\n this.buildAllTask = this.project.tasks.addTask(ROOT_CI_TASK_NAME, {\n description:\n \"Root build followed by sub-project builds. Mimics the CI build process in one step.\",\n });\n this.buildAllTask.exec(\"turbo telemetry disable\");\n\n /**\n * Any env vars that may need to be added to the build all task.\n */\n if (this.buildAllTaskEnvVars) {\n Object.entries(this.buildAllTaskEnvVars).forEach(([name, value]) => {\n this.addGlobalEnvVar(name, value);\n });\n }\n\n /**\n * No remote cache in use, so run the root turbo task to build all\n * sub-projects locally.\n */\n if (!this.remoteCacheOptions) {\n this.buildAllTask.exec(\n `turbo ${ROOT_TURBO_TASK_NAME} --summarize --concurrency=10`,\n );\n } else {\n /**\n * Remote cache in use, so run the root turbo task to build all\n * sub-projects using the remote cache.\n */\n this.buildAllTask.exec(\n `turbo turbo:build --summarize --concurrency=10 --cache=remote:rw --api=$TURBO_ENDPOINT --token=$TURBO_TOKEN --team=${this.remoteCacheOptions.teamName}`,\n {\n condition: '[ ! -n \"$CI\" ]',\n env: {\n TURBO_ENDPOINT: `$(aws ssm get-parameter --name ${this.remoteCacheOptions.endpointParamName} --query Parameter.Value --output text --profile ${this.remoteCacheOptions.profileName})`,\n TURBO_TOKEN: `$(aws ssm get-parameter --name ${this.remoteCacheOptions.tokenParamName} --query Parameter.Value --output text --profile ${this.remoteCacheOptions.profileName})`,\n },\n },\n );\n // running in CI, We'll depend on OIDC auth.\n this.buildAllTask.exec(\n `turbo turbo:build --summarize --concurrency=10 --cache=remote:rw --api=$TURBO_ENDPOINT --token=$TURBO_TOKEN --team=${this.remoteCacheOptions.teamName}`,\n {\n condition: '[ -n \"$CI\" ]',\n env: {\n TURBO_ENDPOINT: `$(aws ssm get-parameter --name ${this.remoteCacheOptions.endpointParamName} --query Parameter.Value --output text)`,\n TURBO_TOKEN: `$(aws ssm get-parameter --name ${this.remoteCacheOptions.tokenParamName} --query Parameter.Value --output text)`,\n },\n },\n );\n }\n }\n\n /**\n * SUB-PROJECT\n *\n * Creates tasks for the typical lifecycle for all project projects.\n */\n if (!this.isRootProject) {\n /**\n * All generated files in the project. Include these as inputs to the\n * compile related tasks.\n */\n const generatedFiles = this.project.components\n .filter((c): c is FileBase => c instanceof FileBase)\n .map((c) => c.path);\n\n this.preCompileTask = new TurboRepoTask(project, {\n name: options.preCompileTask?.name ?? \"pre-compile\",\n inputs: [\"src/**\", ...generatedFiles],\n });\n this.compileTask = new TurboRepoTask(project, {\n name: options.compileTask?.name ?? \"compile\",\n inputs: [\"src/**\", ...generatedFiles],\n });\n this.postCompileTask = new TurboRepoTask(project, {\n name: options.postCompileTask?.name ?? \"post-compile\",\n inputs: [\"src/**\", ...generatedFiles],\n });\n this.testTask = new TurboRepoTask(project, {\n name: options.testTask?.name ?? \"test\",\n });\n this.packageTask = new TurboRepoTask(project, {\n name: options.packageTask?.name ?? \"package\",\n inputs: [\".npmignore\"],\n });\n this.tasks.push(\n this.preCompileTask,\n this.compileTask,\n this.postCompileTask,\n this.testTask,\n this.packageTask,\n );\n }\n }\n\n /**\n * Add an env var to the global env vars for all tasks.\n * This will also become an input for the build:all task cache at the root.\n */\n public addGlobalEnvVar(name: string, value: string) {\n /**\n * Add env var to global task env\n */\n this.buildAllTask?.env(name, value);\n\n /**\n * Add to global env vars for all tasks.\n */\n if (this.isRootProject) {\n this.globalEnv.push(name);\n }\n }\n\n /**\n * Sets GIT_BRANCH_NAME so root tasks (e.g. build:all) pass the current branch.\n * Value must be exactly $(...) so Projen's task runtime expands it; the shell\n * then expands ${GIT_BRANCH_NAME:-$(git rev-parse --abbrev-ref HEAD)}.\n */\n public activateBranchNameEnvVar() {\n this.addGlobalEnvVar(\n \"GIT_BRANCH_NAME\",\n '$(echo \"${GIT_BRANCH_NAME:-$(git rev-parse --abbrev-ref HEAD)}\")',\n );\n }\n\n preSynthesize(): void {\n /**\n * Add any local workspace specific deps to dependsOn so that we know\n * compile has finished before attempting to use any distribution artifacts.\n *\n * Do this in presynth so that we can be sure all project dependencies have\n * been defined first.\n */\n let nextDependsOn = this.project.deps.all\n .filter((d) => d.version === \"workspace:*\")\n .map((d) => [d.name, ROOT_TURBO_TASK_NAME].join(\"#\"));\n\n /**\n * Loop over all projen tasks and their corresponding turbo task\n * definitions. Chain them together using dependsOn, along with any outside\n * package dependencies.\n */\n if (!this.isRootProject) {\n (\n [\n [this.project.preCompileTask, this.preCompileTask],\n [this.project.compileTask, this.compileTask],\n [this.project.postCompileTask, this.postCompileTask],\n [this.project.testTask, this.testTask],\n [this.project.packageTask, this.packageTask],\n ] as Array<[Task, TurboRepoTask]>\n ).forEach(([pjTask, turboTask]) => {\n /**\n * If steps exist chain using dependsOn\n */\n if (pjTask && turboTask && pjTask.steps.length > 0) {\n if (nextDependsOn.length > 0) {\n turboTask.dependsOn.push(...nextDependsOn);\n }\n nextDependsOn = [turboTask.name];\n\n /**\n * Otherwise, if a task doesn't do anything, deactivate it.\n */\n } else {\n turboTask.isActive = false;\n }\n });\n\n /**\n * Main build entry point depends on whatever was last.\n */\n this.buildTask.dependsOn.push(...nextDependsOn);\n }\n\n /**\n * The name for the turbo config file.\n */\n const fileName: string = \"turbo.json\";\n\n /**\n * Ensure that turbo config doesn't end up in any package distributions.\n */\n this.project.addPackageIgnore(fileName);\n\n /**\n * The content of this YAML file will be resolved at synth time. By then,\n * any sub-projects will be defined and this will be a complete list.\n */\n new JsonFile(this.project, fileName, {\n obj: {\n extends: this.extends.length ? this.extends : undefined,\n globalDependencies:\n this.isRootProject && this.globalDependencies.length\n ? this.globalDependencies\n : undefined,\n globalEnv:\n this.isRootProject && this.globalEnv.length\n ? this.globalEnv\n : undefined,\n globalPassThroughEnv:\n this.isRootProject && this.globalPassThroughEnv.length\n ? this.globalPassThroughEnv\n : undefined,\n ui: this.isRootProject ? this.ui : undefined,\n dangerouslyDisablePackageManagerCheck: this.isRootProject\n ? this.dangerouslyDisablePackageManagerCheck\n : undefined,\n cacheDir: this.isRootProject ? this.cacheDir : undefined,\n daemon: this.isRootProject ? this.daemon : undefined,\n envMode: this.isRootProject ? this.envMode : undefined,\n /**\n * All tasks\n */\n tasks: this.tasks\n .filter((task) => task.isActive)\n .reduce(\n (acc, task) => {\n acc[task.name] = {\n ...task.taskConfig(),\n };\n return acc;\n },\n {\n [this.buildTask.name]: { ...this.buildTask.taskConfig() },\n } as Record<string, any>,\n ),\n },\n });\n\n super.preSynthesize();\n }\n}\n","import { Component, Project } from \"projen/lib\";\n\n/**\n * Each of the below options corresponds to a task property found here:\n * * https://turborepo.com/docs/reference/configuration#defining-tasks\n */\nexport interface TurboRepoTaskOptions {\n readonly name: string;\n readonly dependsOn?: Array<string>;\n readonly env?: Array<string>;\n readonly passThroughEnv?: Array<string>;\n readonly outputs?: Array<string>;\n readonly cache?: boolean;\n readonly inputs?: Array<string>;\n readonly outputLogs?:\n | \"full\"\n | \"hash-only\"\n | \"new-only\"\n | \"errors-only\"\n | \"none\";\n readonly persistent?: boolean;\n readonly interactive?: boolean;\n}\n\nexport class TurboRepoTask extends Component {\n public readonly name: string;\n public dependsOn: Array<string>;\n public readonly env: Array<string>;\n public readonly passThroughEnv: Array<string>;\n public outputs: Array<string>;\n public cache: boolean;\n public inputs: Array<string>;\n public readonly outputLogs:\n | \"full\"\n | \"hash-only\"\n | \"new-only\"\n | \"errors-only\"\n | \"none\";\n public readonly persistent: boolean;\n public readonly interactive: boolean;\n\n /**\n * Include this task in turbo.json output?\n */\n public isActive: boolean;\n\n constructor(\n public readonly project: Project,\n options: TurboRepoTaskOptions,\n ) {\n super(project);\n\n this.name = options.name;\n this.dependsOn = options.dependsOn ?? [];\n this.env = options.env ?? [];\n this.passThroughEnv = options.passThroughEnv ?? [];\n this.outputs = options.outputs ?? [];\n this.cache = options.cache ?? true;\n this.inputs = [\n ...(options.inputs ?? []),\n // rerun if projen config changes\n \".projen/**\",\n // ignore mac files\n \"!.DS_Store\",\n \"!**/.DS_Store\",\n ];\n this.outputLogs = options.outputLogs ?? \"new-only\";\n this.persistent = options.persistent ?? false;\n this.interactive = options.interactive ?? false;\n this.isActive = true;\n }\n\n public taskConfig(): Record<string, any> {\n return {\n dependsOn: this.dependsOn,\n env: this.env,\n passThroughEnv: this.passThroughEnv,\n outputs: this.outputs,\n cache: this.cache,\n inputs: this.inputs,\n outputLogs: this.outputLogs,\n persistent: this.persistent,\n interactive: this.interactive,\n };\n }\n}\n","import { Project } from \"projen/lib\";\nimport { TurboRepo } from \"../../turbo/turbo-repo\";\nimport { AgentRuleBundle } from \"../agent-config-options\";\nimport { AGENT_RULE_SCOPE } from \"../types\";\nimport { hasComponent } from \"./utils\";\n\n/**\n * Turborepo bundle — auto-detected when the TurboRepo component is present.\n */\nexport const turborepoBundle: AgentRuleBundle = {\n name: \"turborepo\",\n description: \"Turborepo workspace rules and task pipeline conventions\",\n appliesWhen: (project: Project) => hasComponent(project, TurboRepo),\n rules: [\n {\n name: \"turborepo-conventions\",\n description: \"Turborepo build system and task pipeline conventions\",\n scope: AGENT_RULE_SCOPE.FILE_PATTERN,\n filePatterns: [\"turbo.json\", \"package.json\"],\n content: [\n \"# Turborepo Conventions\",\n \"\",\n \"## Build System\",\n \"\",\n \"- **Build**: `pnpm build:all` (uses Turborepo)\",\n \"- **Test**: `pnpm test` or `pnpm test:watch`\",\n \"- **Lint**: `pnpm eslint`\",\n \"\",\n \"## Task Pipeline\",\n \"\",\n \"- Uses remote caching (requires AWS credentials)\",\n \"- Only rebuilds changed packages\",\n \"- Cache key based on file hashes and dependency graph\",\n \"- Configured in `turbo.json`\",\n \"\",\n \"## Workspace Rules\",\n \"\",\n \"- Source files: `src/` directory\",\n \"- Tests: Co-located with source files (`.spec.ts` or `.test.ts`)\",\n \"- Exports: Use `index.ts` files for clean public APIs\",\n \"- Configuration: Managed by Projen (edit `.projenrc.ts` or `projenrc/*.ts`)\",\n ].join(\"\\n\"),\n tags: [\"workflow\"],\n },\n ],\n claudePermissions: {\n allow: [\"Bash(npx turbo:*)\"],\n },\n};\n","import { Project } from \"projen/lib\";\nimport { AgentRuleBundle } from \"../agent-config-options\";\nimport { AGENT_RULE_SCOPE } from \"../types\";\nimport { findProjectsWithFile, hasFile } from \"./utils\";\n\n/**\n * TypeScript bundle — auto-detected when a tsconfig is present.\n */\nexport const typescriptBundle: AgentRuleBundle = {\n name: \"typescript\",\n description:\n \"TypeScript conventions, type safety, naming, JSDoc, member ordering\",\n appliesWhen: (project: Project) => hasFile(project, \"tsconfig.json\"),\n findApplicableProjects: (project: Project) =>\n findProjectsWithFile(project, \"tsconfig.json\"),\n rules: [\n {\n name: \"typescript-conventions\",\n description: \"TypeScript coding conventions and style guide\",\n scope: AGENT_RULE_SCOPE.FILE_PATTERN,\n filePatterns: [\"**/*.ts\", \"**/*.tsx\"],\n content: [\n \"# TypeScript Conventions\",\n \"\",\n \"## Type Safety\",\n \"\",\n \"- Use **strict TypeScript** with all strict checks enabled\",\n \"- Always use explicit types; avoid `any` unless absolutely necessary\",\n \"- Use `readonly` for immutable properties\",\n \"- Prefer interfaces over types for object shapes\",\n \"- Use proper TypeScript types from libraries\",\n \"\",\n \"## Code Organization\",\n \"\",\n \"- Follow the member ordering rule:\",\n \" 1. Public static fields/methods\",\n \" 2. Protected static fields/methods\",\n \" 3. Private static fields/methods\",\n \" 4. Instance fields\",\n \" 5. Constructor\",\n \" 6. Methods\",\n \"\",\n \"## Documentation\",\n \"\",\n \"- **Keep JSDoc minimal** so that the code remains human-readable. Use brief summaries only.\",\n \"- Use JSDoc for:\",\n \" - Public classes and interfaces (short description)\",\n \" - Public methods and properties (brief purpose; parameter and return when not obvious)\",\n \" - Configuration options (one-line description)\",\n \"- **Extended documentation** belongs in **markdown** files. Link from JSDoc via `@see` or an inline link.\",\n \"\",\n \"## Naming Conventions\",\n \"\",\n \"- **Classes**: PascalCase (e.g., `TypeScriptProject`, `StaticHosting`)\",\n \"- **Interfaces**: PascalCase, often with `Props` suffix for configuration (e.g., `StaticHostingProps`)\",\n \"- **Functions/Methods**: camelCase (e.g., `configureProject`)\",\n \"- **Constants**: UPPER_SNAKE_CASE (e.g., `VERSION`, `AWS_STAGE_TYPE`)\",\n \"- **Files**: kebab-case for multi-word files (e.g., `aws-deployment-config.ts`)\",\n \"- **Component file naming**: kebab-case filename must mirror the PascalCase class name (e.g., `ResetTask` → `reset-task.ts`)\",\n \"- **Private members**: No prefix needed (TypeScript handles visibility)\",\n \"\",\n \"## Array Type Syntax\",\n \"\",\n \"- Prefer `Array<T>` over `T[]` for readability\",\n \"- For nested generics this is especially important: `Array<Array<string>>` is clearer than `string[][]`\",\n \"\",\n \"## Enum Preference\",\n \"\",\n \"- Prefer `as const` objects over TypeScript `enum` declarations\",\n \"- `as const` objects are more flexible: they support computed values, work with `keyof typeof`, and tree-shake better\",\n \"- Example:\",\n \" ```typescript\",\n \" // Prefer this:\",\n \" const Status = { Active: 'active', Inactive: 'inactive' } as const;\",\n \" type Status = (typeof Status)[keyof typeof Status];\",\n \"\",\n \" // Over this:\",\n \" enum Status { Active = 'active', Inactive = 'inactive' }\",\n \" ```\",\n ].join(\"\\n\"),\n tags: [\"coding\"],\n },\n ],\n claudePermissions: {\n allow: [\"Bash(npx tsc:*)\"],\n },\n};\n","import { Component } from \"projen\";\nimport { Jest, NodeProject } from \"projen/lib/javascript\";\nimport { TextFile } from \"projen/lib/textfile\";\nimport { VERSION } from \"../versions\";\n\n/**\n * Options for the Vitest config (test block in vitest.config).\n *\n * @see https://vitest.dev/config/\n */\nexport interface VitestConfigOptions {\n /**\n * Glob patterns for test files.\n *\n * @default [\"**\\/*.{test,spec}.?(c|m)[jt]s?(x)\"]\n */\n readonly include?: string[];\n\n /**\n * Glob patterns to exclude from test files.\n *\n * @default [\"**\\/node_modules\\/**\", \"**\\/dist\\/**\", \"**\\/lib\\/**\", \"**\\/.?\\*\"]\n */\n readonly exclude?: string[];\n\n /**\n * Test environment.\n *\n * @default \"node\"\n */\n readonly environment?: \"node\" | \"jsdom\" | \"happy-dom\" | \"edge-runtime\";\n\n /**\n * Do not fail when no tests are found.\n *\n * @default true\n */\n readonly passWithNoTests?: boolean;\n\n /**\n * Enable coverage collection.\n *\n * @default true\n */\n readonly coverageEnabled?: boolean;\n\n /**\n * Coverage reports directory.\n *\n * @default \"coverage\"\n */\n readonly coverageDirectory?: string;\n\n /**\n * Coverage reporters.\n *\n * @default [\"text\", \"lcov\"]\n */\n readonly coverageReporters?: string[];\n}\n\n/**\n * Options for the Vitest component.\n */\nexport interface VitestOptions {\n /**\n * Config file path.\n *\n * @default \"vitest.config.ts\"\n */\n readonly configFilePath?: string;\n\n /**\n * Vitest config (test block).\n */\n readonly config?: VitestConfigOptions;\n\n /**\n * Vitest version (overrides VERSION.VITEST_VERSION).\n */\n readonly vitestVersion?: string;\n}\n\n/**\n * Vitest component for Node/TypeScript projects.\n *\n * Adds Vitest as the test runner: devDeps, vitest.config.ts, and test/watch tasks.\n * Incompatible with Jest; use jest: false when constructing the project.\n */\nexport class Vitest extends Component {\n /**\n * Find the Vitest component on a project.\n */\n public static of(project: NodeProject): Vitest | undefined {\n const isVitest = (c: Component): c is Vitest => c instanceof Vitest;\n return project.components.find(isVitest);\n }\n\n private readonly configFilePath: string;\n private readonly include: string[];\n private readonly exclude: string[];\n private readonly environment: string;\n private readonly passWithNoTests: boolean;\n private readonly coverageEnabled: boolean;\n private readonly coverageDirectory: string;\n private readonly coverageReporters: string[];\n private readonly version: string;\n\n constructor(\n public readonly project: NodeProject,\n options: VitestOptions = {},\n ) {\n super(project);\n\n this.configFilePath = options.configFilePath ?? \"vitest.config.ts\";\n const config = options.config ?? {};\n this.include = config.include ?? [\"**/*.{test,spec}.?(c|m)[jt]s?(x)\"];\n this.exclude = config.exclude ?? [\n \"**/node_modules/**\",\n \"**/dist/**\",\n \"**/lib/**\",\n \"**/.?*\",\n ];\n this.environment = config.environment ?? \"node\";\n this.passWithNoTests = config.passWithNoTests ?? true;\n this.coverageEnabled = config.coverageEnabled ?? true;\n this.coverageDirectory = config.coverageDirectory ?? \"coverage\";\n this.coverageReporters = config.coverageReporters ?? [\"text\", \"lcov\"];\n this.version = options.vitestVersion ?? VERSION.VITEST_VERSION;\n\n project.addDevDeps(`vitest@${this.version}`);\n if (this.coverageEnabled) {\n project.addDevDeps(`@vitest/coverage-v8@${this.version}`);\n }\n\n const coveragePath = `/${this.coverageDirectory}/`;\n project.gitignore.addPatterns(coveragePath);\n project.npmignore?.exclude(coveragePath);\n\n this.addTestTasks();\n this.synthesizeConfig();\n }\n\n public override preSynthesize(): void {\n super.preSynthesize();\n for (const component of this.project.components) {\n if (component instanceof Jest) {\n throw new Error(\"Vitest cannot be used together with Jest\");\n }\n }\n }\n\n private addTestTasks(): void {\n // No receiveArgs so CI/turbo build:all always get a single run (no watch).\n // --update matches Jest's --updateSnapshot: updates snapshots when they mismatch.\n this.project.testTask.exec(\"vitest run --update\");\n\n if (!this.project.tasks.tryFind(\"test:watch\")) {\n this.project.addTask(\"test:watch\", {\n description: \"Run tests in watch mode\",\n exec: \"vitest watch\",\n receiveArgs: true,\n });\n }\n }\n\n private synthesizeConfig(): void {\n this.project.tryRemoveFile(this.configFilePath);\n new TextFile(this, this.configFilePath, {\n lines: this.renderConfig(),\n });\n }\n\n private renderConfig(): string[] {\n return [\n 'import { defineConfig } from \"vitest/config\";',\n \"\",\n \"export default defineConfig({\",\n \" test: {\",\n ` include: ${JSON.stringify(this.include)},`,\n ` exclude: ${JSON.stringify(this.exclude)},`,\n ` environment: \"${this.environment}\",`,\n ` passWithNoTests: ${this.passWithNoTests},`,\n \" coverage: {\",\n ` enabled: ${this.coverageEnabled},`,\n ` provider: \"v8\",`,\n ` reportsDirectory: \"${this.coverageDirectory}\",`,\n ` reporter: ${JSON.stringify(this.coverageReporters)},`,\n \" },\",\n \" },\",\n \"});\",\n ];\n }\n}\n","export const VERSION = {\n /**\n * Version of Astro to pin for AstroProject scaffolding.\n */\n ASTRO_VERSION: \"6.1.6\",\n\n /**\n * CDK CLI for workflows and command line operations.\n *\n * CLI and lib are versioned separately, so this is the CLI version.\n */\n AWS_CDK_CLI_VERSION: \"2.1118.0\",\n\n /**\n * CDK Version to use for construct projects.\n *\n * CLI and lib are versioned separately, so this is the lib version.\n */\n AWS_CDK_LIB_VERSION: \"2.250.0\",\n\n /**\n * Version of the AWS Constructs library to use.\n */\n AWS_CONSTRUCTS_VERSION: \"10.6.0\",\n\n /**\n * Version of Node.js to use in CI workflows at github actions.\n */\n NODE_WORKFLOWS: \"24\",\n\n /**\n * Version of `pnpm/action-setup` to use in GitHub workflows.\n * Tracks the version projen currently emits (see node_modules/projen/lib/javascript/node-project.js).\n */\n PNPM_ACTION_SETUP_VERSION: \"v5\",\n\n /**\n * Version of PNPM to use in workflows at github actions.\n */\n PNPM_VERSION: \"10.33.0\",\n\n /**\n * Version of Projen to use.\n */\n PROJEN_VERSION: \"0.99.48\",\n\n /**\n * Version of `actions/setup-node` to use in GitHub workflows.\n * Tracks the version projen currently emits (see node_modules/projen/lib/github/workflows.js).\n */\n SETUP_NODE_ACTION_VERSION: \"v6\",\n\n /**\n * Version of sharp to pin for StarlightProject (required peer for\n * Starlight's image optimization pipeline).\n */\n SHARP_VERSION: \"0.34.5\",\n\n /**\n * Version of @astrojs/starlight to pin for StarlightProject scaffolding.\n */\n STARLIGHT_VERSION: \"0.38.3\",\n\n /**\n * What version of the turborepo library should we use?\n */\n TURBO_VERSION: \"2.9.6\",\n\n /**\n * Version of @types/node to use across all packages (pnpm catalog).\n */\n TYPES_NODE_VERSION: \"25.6.0\",\n\n /**\n * What version of Vite to use (pnpm override). Pinned to 5.x so Vitest 4.x\n * can load config (Vite 6+/7+ are ESM-only; see issue #142). Remove override\n * when moving to ESM-only test setup.\n */\n VITE_VERSION: \"5.4.11\",\n\n /**\n * What version of Vitest to use when testRunner is 'vitest'.\n * Pinned to 3.x so it works with Vite 5 (Vitest 4 requires Vite 6). See issue #142.\n */\n VITEST_VERSION: \"3.2.4\",\n} as const;\n","import { Project } from \"projen/lib\";\nimport { Vitest } from \"../../vitest/vitest-component\";\nimport { AgentRuleBundle } from \"../agent-config-options\";\nimport { AGENT_RULE_SCOPE } from \"../types\";\nimport { findProjectsWithComponent, hasComponent } from \"./utils\";\n\n/**\n * Vitest bundle — auto-detected when the Vitest component is present.\n */\nexport const vitestBundle: AgentRuleBundle = {\n name: \"vitest\",\n description: \"Vitest testing conventions, patterns, and file scoping\",\n appliesWhen: (project: Project) => hasComponent(project, Vitest),\n findApplicableProjects: (project: Project) =>\n findProjectsWithComponent(project, Vitest),\n rules: [\n {\n name: \"vitest-testing\",\n description: \"Vitest testing conventions and patterns\",\n scope: AGENT_RULE_SCOPE.FILE_PATTERN,\n filePatterns: [\"**/*.test.ts\", \"**/*.spec.ts\"],\n content: [\n \"# Vitest Testing Patterns\",\n \"\",\n \"## Mandatory Requirements\",\n \"\",\n \"- **Tests MUST be created or updated whenever code functionality is added or changed**\",\n \"- This applies to all code changes, including:\",\n \" - New features and functionality\",\n \" - Bug fixes\",\n \" - Refactoring that changes behavior\",\n \" - API changes\",\n \" - Configuration changes that affect functionality\",\n \"- Tests should be written or updated as part of the same change that modifies the code\",\n \"\",\n \"## Test Structure\",\n \"\",\n \"- Use **Vitest** as the test runner\",\n \"- Test files: `.spec.ts` or `.test.ts` (co-located with source)\",\n \"- Use descriptive test names: `describe('ClassName', () => { it('should do something specific', () => {}) })`\",\n \"- Prefer snapshot tests for complex object structures\",\n \"- Mock external dependencies appropriately\",\n \"\",\n \"## Test Organization\",\n \"\",\n \"- Co-locate test files with source files\",\n \"- Test files can use dev dependencies (ESLint rule override)\",\n \"- Import from `vitest`: `import { describe, expect, it } from 'vitest'`\",\n \"\",\n \"## Example Test Structure\",\n \"\",\n \"```typescript\",\n \"import { describe, expect, it } from 'vitest';\",\n \"import { MyClass } from './my-class';\",\n \"\",\n \"describe('MyClass', () => {\",\n \" it('should do something specific', () => {\",\n \" // Test implementation\",\n \" });\",\n \"});\",\n \"```\",\n ].join(\"\\n\"),\n tags: [\"testing\"],\n },\n ],\n claudePermissions: {\n allow: [\"Bash(npx vitest:*)\"],\n },\n};\n","import { AgentRuleBundle } from \"../agent-config-options\";\nimport { awsCdkBundle } from \"./aws-cdk\";\nimport { baseBundle } from \"./base\";\nimport { bcmWriterBundle } from \"./bcm-writer\";\nimport { companyProfileBundle } from \"./company-profile\";\nimport { githubWorkflowBundle } from \"./github-workflow\";\nimport { industryDiscoveryBundle } from \"./industry-discovery\";\nimport { jestBundle } from \"./jest\";\nimport { maintenanceAuditBundle } from \"./maintenance-audit\";\nimport { meetingAnalysisBundle } from \"./meeting-analysis\";\nimport { orchestratorBundle } from \"./orchestrator\";\nimport { peopleProfileBundle } from \"./people-profile\";\nimport { pnpmBundle } from \"./pnpm\";\nimport { prReviewBundle } from \"./pr-review\";\nimport { projenBundle } from \"./projen\";\nimport { requirementsAnalystBundle } from \"./requirements-analyst\";\nimport { requirementsWriterBundle } from \"./requirements-writer\";\nimport { researchPipelineBundle } from \"./research-pipeline\";\nimport { slackBundle } from \"./slack\";\nimport { softwareProfileBundle } from \"./software-profile\";\nimport { turborepoBundle } from \"./turborepo\";\nimport { typescriptBundle } from \"./typescript\";\nimport { vitestBundle } from \"./vitest\";\n\nexport { awsCdkBundle } from \"./aws-cdk\";\nexport { baseBundle } from \"./base\";\nexport { bcmWriterBundle } from \"./bcm-writer\";\nexport { companyProfileBundle } from \"./company-profile\";\nexport { githubWorkflowBundle } from \"./github-workflow\";\nexport { industryDiscoveryBundle } from \"./industry-discovery\";\nexport { jestBundle } from \"./jest\";\nexport { maintenanceAuditBundle } from \"./maintenance-audit\";\nexport { meetingAnalysisBundle } from \"./meeting-analysis\";\nexport { orchestratorBundle } from \"./orchestrator\";\nexport { peopleProfileBundle } from \"./people-profile\";\nexport { pnpmBundle } from \"./pnpm\";\nexport { prReviewBundle } from \"./pr-review\";\nexport { projenBundle } from \"./projen\";\nexport { requirementsAnalystBundle } from \"./requirements-analyst\";\nexport { requirementsWriterBundle } from \"./requirements-writer\";\nexport { researchPipelineBundle } from \"./research-pipeline\";\nexport { slackBundle } from \"./slack\";\nexport { softwareProfileBundle } from \"./software-profile\";\nexport { turborepoBundle } from \"./turborepo\";\nexport { typescriptBundle } from \"./typescript\";\nexport { vitestBundle } from \"./vitest\";\n\n/**\n * Built-in rule bundles that ship with configulator.\n * Each bundle is auto-detected based on project introspection.\n *\n * Order matters: base is first so its rules can be overridden by\n * more specific bundles. The base bundle's `appliesWhen` always\n * returns true; it is filtered by the `includeBaseRules` option\n * in AgentConfig.\n */\nexport const BUILT_IN_BUNDLES: ReadonlyArray<AgentRuleBundle> = [\n baseBundle,\n typescriptBundle,\n vitestBundle,\n jestBundle,\n turborepoBundle,\n pnpmBundle,\n awsCdkBundle,\n projenBundle,\n githubWorkflowBundle,\n slackBundle,\n meetingAnalysisBundle,\n orchestratorBundle,\n prReviewBundle,\n requirementsAnalystBundle,\n requirementsWriterBundle,\n researchPipelineBundle,\n companyProfileBundle,\n peopleProfileBundle,\n softwareProfileBundle,\n industryDiscoveryBundle,\n bcmWriterBundle,\n maintenanceAuditBundle,\n];\n","import * as path from \"node:path\";\nimport { Project } from \"projen/lib\";\n\n/**\n * Minimal shape projen's `TypescriptConfig` exposes for reading back the\n * final `include` array. We duck-type against it because non-TypeScript\n * projects don't have `tsconfig` at all.\n */\ninterface TypescriptConfigLike {\n readonly include: ReadonlyArray<string>;\n}\n\ninterface WithTsconfig {\n readonly tsconfig?: TypescriptConfigLike;\n}\n\ninterface WithSrcdir {\n readonly srcdir?: string;\n}\n\n/**\n * For each detected project, read its `tsconfig.include` and prefix each\n * entry with the project's outdir relative to the root. Returns a\n * deduplicated, sorted array of scoped glob patterns suitable for use as a\n * rule's `filePatterns`.\n *\n * Projects without a `tsconfig` fall back to `<relOutdir>/<srcdir>/**\\/*.ts`\n * (srcdir defaults to `\"src\"`), which matches projen's defaults for any\n * plain `TypeScriptProject`.\n */\nexport function scopeFilePatternsToProjects(\n root: Project,\n detected: ReadonlyArray<Project>,\n): Array<string> {\n const patterns = new Set<string>();\n\n for (const project of detected) {\n const rel = path.relative(root.outdir, project.outdir);\n const include = readTsconfigInclude(project);\n\n if (include && include.length > 0) {\n for (const entry of include) {\n patterns.add(prefix(rel, entry));\n }\n } else {\n const srcdir = (project as WithSrcdir).srcdir ?? \"src\";\n patterns.add(prefix(rel, path.posix.join(srcdir, \"**/*.ts\")));\n }\n }\n\n return [...patterns].sort();\n}\n\n/**\n * Read the `tsconfig.include` array from a projen Project, if present.\n * Returns `undefined` for projects without a tsconfig component.\n */\nfunction readTsconfigInclude(\n project: Project,\n): ReadonlyArray<string> | undefined {\n const tsconfig = (project as WithTsconfig).tsconfig;\n if (!tsconfig) {\n return undefined;\n }\n return tsconfig.include;\n}\n\n/**\n * Join a project-relative prefix with a glob entry using POSIX separators so\n * rendered rule files are stable across platforms. An empty `rel` means the\n * detected project is the root itself — return the entry unchanged.\n */\nfunction prefix(rel: string, entry: string): string {\n if (!rel) {\n return entry;\n }\n return path.posix.join(rel, entry);\n}\n","import { Component, JsonFile } from \"projen\";\nimport { TextFile } from \"projen/lib/textfile\";\nimport { ClaudeSettingsConfig } from \"../agent-config-options\";\nimport {\n AGENT_RULE_SCOPE,\n AgentProcedure,\n AgentRule,\n AgentSkill,\n AgentSubAgent,\n CLAUDE_RULE_TARGET,\n McpServerConfig,\n resolveModelAlias,\n} from \"../types\";\n\nconst GENERATED_MARKER =\n \"<!-- ~~ Generated by @codedrifters/configulator. Edits welcome — please contribute improvements back. ~~ -->\";\n\n/**\n * Renders agent configuration files for Claude Code.\n *\n * Output files:\n * - CLAUDE.md — always-active rules targeted to CLAUDE_MD\n * - .claude/rules/{name}.md — scoped rules with optional paths frontmatter\n * - .claude/settings.json — permissions, hooks, MCP servers, sandbox\n * - .claude/skills/{name}/SKILL.md — skill definitions\n * - .claude/agents/{name}.md — sub-agent definitions\n * - .claude/procedures/{name} — executable procedures (shell scripts)\n */\nexport class ClaudeRenderer {\n /**\n * Render all Claude Code configuration files.\n */\n public static render(\n component: Component,\n rules: ReadonlyArray<AgentRule>,\n skills: ReadonlyArray<AgentSkill>,\n subAgents: ReadonlyArray<AgentSubAgent>,\n mcpServers: Readonly<Record<string, McpServerConfig>>,\n settings?: ClaudeSettingsConfig,\n procedures?: ReadonlyArray<AgentProcedure>,\n ): void {\n ClaudeRenderer.renderClaudeMd(component, rules);\n ClaudeRenderer.renderScopedRules(component, rules);\n ClaudeRenderer.renderSettings(component, mcpServers, settings);\n ClaudeRenderer.renderSkills(component, skills);\n ClaudeRenderer.renderSubAgents(component, subAgents);\n if (procedures && procedures.length > 0) {\n ClaudeRenderer.renderProcedures(component, procedures);\n }\n }\n\n private static renderClaudeMd(\n component: Component,\n rules: ReadonlyArray<AgentRule>,\n ): void {\n const claudeMdRules = rules.filter((r) => {\n if (r.platforms?.claude?.exclude) return false;\n const target =\n r.platforms?.claude?.target ?? ClaudeRenderer.defaultTarget(r);\n return target === CLAUDE_RULE_TARGET.CLAUDE_MD;\n });\n\n if (claudeMdRules.length === 0) return;\n\n const lines: string[] = [GENERATED_MARKER, \"\"];\n for (let i = 0; i < claudeMdRules.length; i++) {\n if (i > 0) lines.push(\"\", \"---\", \"\");\n lines.push(...claudeMdRules[i].content.split(\"\\n\"));\n }\n\n new TextFile(component, \"CLAUDE.md\", { lines });\n }\n\n private static renderScopedRules(\n component: Component,\n rules: ReadonlyArray<AgentRule>,\n ): void {\n const scopedRules = rules.filter((r) => {\n if (r.platforms?.claude?.exclude) return false;\n const target =\n r.platforms?.claude?.target ?? ClaudeRenderer.defaultTarget(r);\n return target === CLAUDE_RULE_TARGET.SCOPED_FILE;\n });\n\n for (const rule of scopedRules) {\n const lines: string[] = [];\n\n if (rule.filePatterns && rule.filePatterns.length > 0) {\n lines.push(\"---\");\n lines.push(\"paths:\");\n for (const pattern of rule.filePatterns) {\n lines.push(` - \"${pattern}\"`);\n }\n lines.push(\"---\");\n lines.push(\"\");\n }\n\n lines.push(...rule.content.split(\"\\n\"));\n\n new TextFile(component, `.claude/rules/${rule.name}.md`, { lines });\n }\n }\n\n private static renderSettings(\n component: Component,\n mcpServers: Readonly<Record<string, McpServerConfig>>,\n settings?: ClaudeSettingsConfig,\n ): void {\n const obj: Record<string, unknown> = {};\n let hasContent = false;\n\n if (settings?.defaultMode) {\n obj.defaultMode = settings.defaultMode;\n hasContent = true;\n }\n\n if (settings?.permissions) {\n const perms: Record<string, unknown> = {};\n if (settings.permissions.allow?.length) {\n perms.allow = [...settings.permissions.allow];\n }\n if (settings.permissions.deny?.length) {\n perms.deny = [...settings.permissions.deny];\n }\n if (settings.permissions.ask?.length) {\n perms.ask = [...settings.permissions.ask];\n }\n if (settings.permissions.additionalDirectories?.length) {\n perms.additionalDirectories = [\n ...settings.permissions.additionalDirectories,\n ];\n }\n if (Object.keys(perms).length > 0) {\n obj.permissions = perms;\n hasContent = true;\n }\n }\n\n if (settings?.hooks) {\n const hooks: Record<string, unknown> = {};\n for (const [event, entries] of Object.entries(settings.hooks)) {\n if (entries && entries.length > 0) {\n hooks[event] = entries;\n }\n }\n if (Object.keys(hooks).length > 0) {\n obj.hooks = hooks;\n hasContent = true;\n }\n }\n\n // MCP servers from both cross-platform and Claude-specific config\n const allMcpServers: Record<string, unknown> = {};\n\n // Cross-platform MCP servers\n for (const [name, config] of Object.entries(mcpServers)) {\n allMcpServers[name] = ClaudeRenderer.buildMcpServerObj(config);\n }\n\n // Claude-specific MCP servers\n if (settings?.mcpServers) {\n for (const [name, config] of Object.entries(settings.mcpServers)) {\n allMcpServers[name] = ClaudeRenderer.buildMcpServerObj(config);\n }\n }\n\n if (Object.keys(allMcpServers).length > 0) {\n obj.mcpServers = allMcpServers;\n hasContent = true;\n }\n\n if (settings?.allowedMcpServers?.length) {\n obj.allowedMcpServers = [...settings.allowedMcpServers];\n hasContent = true;\n }\n\n if (settings?.deniedMcpServers?.length) {\n obj.deniedMcpServers = [...settings.deniedMcpServers];\n hasContent = true;\n }\n\n if (settings?.env && Object.keys(settings.env).length > 0) {\n obj.env = { ...settings.env };\n hasContent = true;\n }\n\n if (settings?.sandbox) {\n obj.sandbox = ClaudeRenderer.buildSandboxObj(settings.sandbox);\n hasContent = true;\n }\n\n if (settings?.autoMode) {\n const autoMode: Record<string, unknown> = {};\n if (settings.autoMode.environment?.length) {\n autoMode.environment = [...settings.autoMode.environment];\n }\n if (settings.autoMode.allow?.length) {\n autoMode.allow = [...settings.autoMode.allow];\n }\n if (settings.autoMode.soft_deny?.length) {\n autoMode.soft_deny = [...settings.autoMode.soft_deny];\n }\n if (Object.keys(autoMode).length > 0) {\n obj.autoMode = autoMode;\n hasContent = true;\n }\n }\n\n if (settings?.disableBypassPermissionsMode) {\n obj.disableBypassPermissionsMode = settings.disableBypassPermissionsMode;\n hasContent = true;\n }\n\n if (settings?.disableAutoMode) {\n obj.disableAutoMode = settings.disableAutoMode;\n hasContent = true;\n }\n\n if (settings?.disableAllHooks !== undefined) {\n obj.disableAllHooks = settings.disableAllHooks;\n hasContent = true;\n }\n\n if (settings?.excludeSensitivePatterns?.length) {\n obj.excludeSensitivePatterns = [...settings.excludeSensitivePatterns];\n hasContent = true;\n }\n\n if (settings?.model) {\n obj.model = settings.model;\n hasContent = true;\n }\n\n if (settings?.effortLevel) {\n obj.effortLevel = settings.effortLevel;\n hasContent = true;\n }\n\n if (settings?.attribution) {\n obj.attribution = settings.attribution;\n hasContent = true;\n }\n\n if (settings?.claudeMdExcludes?.length) {\n obj.claudeMdExcludes = [...settings.claudeMdExcludes];\n hasContent = true;\n }\n\n if (settings?.respectGitignore !== undefined) {\n obj.respectGitignore = settings.respectGitignore;\n hasContent = true;\n }\n\n if (!hasContent) return;\n\n new JsonFile(component, \".claude/settings.json\", { obj });\n }\n\n private static buildSandboxObj(\n sandbox: NonNullable<ClaudeSettingsConfig[\"sandbox\"]>,\n ): Record<string, unknown> {\n const obj: Record<string, unknown> = {};\n if (sandbox.enabled !== undefined) obj.enabled = sandbox.enabled;\n if (sandbox.mode) obj.mode = sandbox.mode;\n if (sandbox.failIfUnavailable !== undefined) {\n obj.failIfUnavailable = sandbox.failIfUnavailable;\n }\n if (sandbox.autoAllowBashIfSandboxed !== undefined) {\n obj.autoAllowBashIfSandboxed = sandbox.autoAllowBashIfSandboxed;\n }\n if (sandbox.excludedCommands?.length) {\n obj.excludedCommands = [...sandbox.excludedCommands];\n }\n if (sandbox.filesystem) {\n const fs: Record<string, unknown> = {};\n if (sandbox.filesystem.allowRead?.length) {\n fs.allowRead = [...sandbox.filesystem.allowRead];\n }\n if (sandbox.filesystem.denyRead?.length) {\n fs.denyRead = [...sandbox.filesystem.denyRead];\n }\n if (sandbox.filesystem.allowWrite?.length) {\n fs.allowWrite = [...sandbox.filesystem.allowWrite];\n }\n if (sandbox.filesystem.denyWrite?.length) {\n fs.denyWrite = [...sandbox.filesystem.denyWrite];\n }\n if (Object.keys(fs).length > 0) obj.filesystem = fs;\n }\n if (sandbox.network) {\n const net: Record<string, unknown> = {};\n if (sandbox.network.allowedDomains?.length) {\n net.allowedDomains = [...sandbox.network.allowedDomains];\n }\n if (sandbox.network.denyDomains?.length) {\n net.denyDomains = [...sandbox.network.denyDomains];\n }\n if (Object.keys(net).length > 0) obj.network = net;\n }\n return obj;\n }\n\n private static renderSkills(\n component: Component,\n skills: ReadonlyArray<AgentSkill>,\n ): void {\n for (const skill of skills) {\n if (skill.platforms?.claude?.exclude) continue;\n\n const lines: string[] = [];\n lines.push(\"---\");\n lines.push(`name: \"${skill.name}\"`);\n lines.push(`description: \"${skill.description}\"`);\n if (skill.disableModelInvocation) {\n lines.push(`disable-model-invocation: true`);\n }\n if (skill.userInvocable === false) {\n lines.push(`user-invocable: false`);\n }\n const resolvedSkillModel = resolveModelAlias(skill.model);\n if (resolvedSkillModel) {\n lines.push(`model: \"${resolvedSkillModel}\"`);\n }\n if (skill.effort) {\n lines.push(`effort: \"${skill.effort}\"`);\n }\n if (skill.paths && skill.paths.length > 0) {\n lines.push(`paths:`);\n for (const p of skill.paths) {\n lines.push(` - \"${p}\"`);\n }\n }\n if (skill.context) {\n lines.push(`context: \"${skill.context}\"`);\n }\n if (skill.agent) {\n lines.push(`agent: \"${skill.agent}\"`);\n }\n if (skill.shell) {\n lines.push(`shell: \"${skill.shell}\"`);\n }\n if (skill.allowedTools && skill.allowedTools.length > 0) {\n lines.push(`allowed-tools:`);\n for (const tool of skill.allowedTools) {\n lines.push(` - \"${tool}\"`);\n }\n }\n lines.push(\"---\");\n lines.push(\"\");\n lines.push(...skill.instructions.split(\"\\n\"));\n\n new TextFile(component, `.claude/skills/${skill.name}/SKILL.md`, {\n lines,\n });\n\n if (skill.referenceFiles && skill.referenceFiles.length > 0) {\n for (const file of skill.referenceFiles) {\n new TextFile(component, `.claude/skills/${skill.name}/${file.path}`, {\n lines: file.content.split(\"\\n\"),\n });\n }\n }\n }\n }\n\n private static renderSubAgents(\n component: Component,\n subAgents: ReadonlyArray<AgentSubAgent>,\n ): void {\n for (const agent of subAgents) {\n if (agent.platforms?.claude?.exclude) continue;\n\n const lines: string[] = [];\n lines.push(\"---\");\n lines.push(`name: ${agent.name}`);\n lines.push(`description: >-`);\n lines.push(` ${agent.description}`);\n const resolvedModel = resolveModelAlias(agent.model);\n if (resolvedModel) {\n lines.push(`model: ${resolvedModel}`);\n }\n if (agent.tools && agent.tools.length > 0) {\n lines.push(`tools:`);\n for (const tool of agent.tools) {\n lines.push(` - \"${tool}\"`);\n }\n }\n if (agent.disallowedTools && agent.disallowedTools.length > 0) {\n lines.push(`disallowedTools:`);\n for (const tool of agent.disallowedTools) {\n lines.push(` - \"${tool}\"`);\n }\n }\n if (agent.maxTurns) {\n lines.push(`maxTurns: ${agent.maxTurns}`);\n }\n if (agent.skills && agent.skills.length > 0) {\n lines.push(`skills:`);\n for (const skill of agent.skills) {\n lines.push(` - \"${skill}\"`);\n }\n }\n if (agent.platforms?.claude?.permissionMode) {\n lines.push(`permissionMode: ${agent.platforms.claude.permissionMode}`);\n }\n if (agent.platforms?.claude?.isolation) {\n lines.push(`isolation: ${agent.platforms.claude.isolation}`);\n }\n if (agent.platforms?.claude?.background) {\n lines.push(`background: true`);\n }\n if (agent.platforms?.claude?.effort) {\n lines.push(`effort: ${agent.platforms.claude.effort}`);\n }\n if (agent.platforms?.claude?.memory) {\n lines.push(`memory: ${agent.platforms.claude.memory}`);\n }\n if (agent.canDelegateToAgents && agent.canDelegateToAgents.length > 0) {\n lines.push(`canDelegateToAgents:`);\n for (const delegateName of agent.canDelegateToAgents) {\n lines.push(` - \"${delegateName}\"`);\n }\n }\n lines.push(\"---\");\n lines.push(\"\");\n lines.push(...agent.prompt.split(\"\\n\"));\n\n new TextFile(component, `.claude/agents/${agent.name}.md`, { lines });\n }\n }\n\n private static buildMcpServerObj(\n config: McpServerConfig,\n ): Record<string, unknown> {\n const server: Record<string, unknown> = {};\n if (config.transport) server.type = config.transport;\n if (config.command) server.command = config.command;\n if (config.args) server.args = [...config.args];\n if (config.url) server.url = config.url;\n if (config.headers && Object.keys(config.headers).length > 0) {\n server.headers = { ...config.headers };\n }\n if (config.env) server.env = { ...config.env };\n return server;\n }\n\n private static renderProcedures(\n component: Component,\n procedures: ReadonlyArray<AgentProcedure>,\n ): void {\n for (const proc of procedures) {\n new TextFile(component, `.claude/procedures/${proc.name}`, {\n lines: proc.content.split(\"\\n\"),\n executable: true,\n });\n }\n }\n\n /**\n * Determine the default Claude rule target based on rule scope.\n * ALWAYS-scoped rules default to CLAUDE_MD; FILE_PATTERN rules default to SCOPED_FILE.\n */\n private static defaultTarget(rule: AgentRule): string {\n return rule.scope === AGENT_RULE_SCOPE.ALWAYS\n ? CLAUDE_RULE_TARGET.CLAUDE_MD\n : CLAUDE_RULE_TARGET.SCOPED_FILE;\n }\n}\n","import { Component } from \"projen\";\nimport { AgentRule, AgentSkill, AgentSubAgent } from \"../types\";\n\n/**\n * Renders agent configuration files for OpenAI Codex.\n *\n * Output files (future):\n * - AGENTS.md — root-level instructions\n * - {dir}/AGENTS.md — directory-scoped instructions\n *\n * TODO: Implement in a future issue.\n */\nexport class CodexRenderer {\n public static render(\n _component: Component,\n _rules: ReadonlyArray<AgentRule>,\n _skills: ReadonlyArray<AgentSkill>,\n _subAgents: ReadonlyArray<AgentSubAgent>,\n ): void {\n // Codex renderer is not yet implemented.\n }\n}\n","import { Component } from \"projen\";\nimport { AgentRule, AgentSkill, AgentSubAgent } from \"../types\";\n\n/**\n * Renders agent configuration files for GitHub Copilot.\n *\n * Output files (future):\n * - .github/copilot-instructions.md — root instructions\n * - .github/instructions/*.instructions.md — scoped instructions\n *\n * TODO: Implement in a future issue.\n */\nexport class CopilotRenderer {\n public static render(\n _component: Component,\n _rules: ReadonlyArray<AgentRule>,\n _skills: ReadonlyArray<AgentSkill>,\n _subAgents: ReadonlyArray<AgentSubAgent>,\n ): void {\n // Copilot renderer is not yet implemented.\n }\n}\n","import { Component, JsonFile } from \"projen\";\nimport { TextFile } from \"projen/lib/textfile\";\nimport { CursorSettingsConfig } from \"../agent-config-options\";\nimport {\n AGENT_RULE_SCOPE,\n AgentRule,\n AgentSkill,\n AgentSubAgent,\n McpServerConfig,\n} from \"../types\";\n\nconst GENERATED_MARKER =\n \"# ~~ Generated by @codedrifters/configulator. Edits welcome — please contribute improvements back. ~~\";\n\n/**\n * Renders agent configuration files for Cursor.\n *\n * Output files:\n * - .cursor/rules/{name}.mdc — YAML frontmatter + markdown body\n * - .cursor/agents/{name}.md — sub-agent definitions\n * - .cursor/mcp.json — MCP server configuration\n * - .cursor/hooks.json — lifecycle hooks\n * - .cursorignore — hard security boundary\n * - .cursorindexingignore — soft indexing boundary\n */\nexport class CursorRenderer {\n /**\n * Render all Cursor configuration files.\n */\n public static render(\n component: Component,\n rules: ReadonlyArray<AgentRule>,\n skills: ReadonlyArray<AgentSkill>,\n subAgents: ReadonlyArray<AgentSubAgent>,\n mcpServers: Readonly<Record<string, McpServerConfig>>,\n settings?: CursorSettingsConfig,\n ): void {\n CursorRenderer.renderRules(component, rules);\n CursorRenderer.renderSkills(component, skills);\n CursorRenderer.renderSubAgents(component, subAgents);\n CursorRenderer.renderMcpServers(component, mcpServers);\n CursorRenderer.renderHooks(component, settings);\n CursorRenderer.renderIgnoreFiles(component, settings);\n }\n\n private static renderRules(\n component: Component,\n rules: ReadonlyArray<AgentRule>,\n ): void {\n for (const rule of rules) {\n if (rule.platforms?.cursor?.exclude) continue;\n\n const lines: string[] = [];\n const description =\n rule.platforms?.cursor?.description ?? rule.description;\n const isAlways = rule.scope === AGENT_RULE_SCOPE.ALWAYS;\n\n // YAML frontmatter\n lines.push(\"---\");\n lines.push(`description: \"${description}\"`);\n lines.push(`alwaysApply: ${isAlways}`);\n if (!isAlways && rule.filePatterns && rule.filePatterns.length > 0) {\n lines.push(`path: ${JSON.stringify([...rule.filePatterns])}`);\n }\n lines.push(\"---\");\n lines.push(\"\");\n lines.push(...rule.content.split(\"\\n\"));\n\n new TextFile(component, `.cursor/rules/${rule.name}.mdc`, { lines });\n }\n }\n\n private static renderSkills(\n component: Component,\n skills: ReadonlyArray<AgentSkill>,\n ): void {\n for (const skill of skills) {\n if (skill.platforms?.cursor?.exclude) continue;\n\n const lines: string[] = [];\n lines.push(\"---\");\n lines.push(`name: \"${skill.name}\"`);\n lines.push(`description: \"${skill.description}\"`);\n if (skill.disableModelInvocation) {\n lines.push(`disable-model-invocation: true`);\n }\n if (skill.userInvocable === false) {\n lines.push(`user-invocable: false`);\n }\n if (skill.context) {\n lines.push(`context: \"${skill.context}\"`);\n }\n if (skill.agent) {\n lines.push(`agent: \"${skill.agent}\"`);\n }\n if (skill.shell) {\n lines.push(`shell: \"${skill.shell}\"`);\n }\n if (skill.allowedTools && skill.allowedTools.length > 0) {\n lines.push(`allowed-tools:`);\n for (const tool of skill.allowedTools) {\n lines.push(` - \"${tool}\"`);\n }\n }\n lines.push(\"---\");\n lines.push(\"\");\n lines.push(...skill.instructions.split(\"\\n\"));\n\n new TextFile(component, `.cursor/skills/${skill.name}/SKILL.md`, {\n lines,\n });\n\n if (skill.referenceFiles && skill.referenceFiles.length > 0) {\n for (const file of skill.referenceFiles) {\n new TextFile(component, `.cursor/skills/${skill.name}/${file.path}`, {\n lines: file.content.split(\"\\n\"),\n });\n }\n }\n }\n }\n\n private static renderSubAgents(\n component: Component,\n subAgents: ReadonlyArray<AgentSubAgent>,\n ): void {\n for (const agent of subAgents) {\n if (agent.platforms?.cursor?.exclude) continue;\n\n const lines: string[] = [];\n lines.push(\"---\");\n lines.push(`name: ${agent.name}`);\n lines.push(`description: >-`);\n lines.push(` ${agent.description}`);\n // Cursor uses its own model selection; omit the model field\n // to let it use its default (e.g., composer).\n if (agent.platforms?.cursor?.readonly) {\n lines.push(`readonly: true`);\n }\n if (agent.platforms?.cursor?.isBackground) {\n lines.push(`is_background: true`);\n }\n lines.push(\"---\");\n lines.push(\"\");\n lines.push(...agent.prompt.split(\"\\n\"));\n\n new TextFile(component, `.cursor/agents/${agent.name}.md`, { lines });\n }\n }\n\n private static renderMcpServers(\n component: Component,\n mcpServers: Readonly<Record<string, McpServerConfig>>,\n ): void {\n const serverNames = Object.keys(mcpServers);\n if (serverNames.length === 0) return;\n\n const obj: Record<string, unknown> = { mcpServers: {} };\n const servers = obj.mcpServers as Record<string, unknown>;\n\n for (const [name, config] of Object.entries(mcpServers)) {\n const server: Record<string, unknown> = {};\n if (config.transport) server.transport = config.transport;\n if (config.command) server.command = config.command;\n if (config.args) server.args = [...config.args];\n if (config.url) server.url = config.url;\n if (config.headers && Object.keys(config.headers).length > 0) {\n server.headers = { ...config.headers };\n }\n if (config.env) server.env = { ...config.env };\n servers[name] = server;\n }\n\n new JsonFile(component, \".cursor/mcp.json\", { obj });\n }\n\n private static renderHooks(\n component: Component,\n settings?: CursorSettingsConfig,\n ): void {\n if (!settings?.hooks) return;\n\n const hooks: Record<string, unknown[]> = {};\n const hookEntries = settings.hooks;\n\n // Render all hook events dynamically\n for (const [event, actions] of Object.entries(hookEntries)) {\n if (actions && actions.length > 0) {\n hooks[event] = actions.map((h: { command: string }) => ({\n command: h.command,\n }));\n }\n }\n\n if (Object.keys(hooks).length === 0) return;\n\n new JsonFile(component, \".cursor/hooks.json\", {\n obj: { version: 1, hooks },\n });\n }\n\n private static renderIgnoreFiles(\n component: Component,\n settings?: CursorSettingsConfig,\n ): void {\n if (settings?.ignorePatterns && settings.ignorePatterns.length > 0) {\n new TextFile(component, \".cursorignore\", {\n lines: [GENERATED_MARKER, \"\", ...settings.ignorePatterns],\n });\n }\n\n if (\n settings?.indexingIgnorePatterns &&\n settings.indexingIgnorePatterns.length > 0\n ) {\n new TextFile(component, \".cursorindexingignore\", {\n lines: [GENERATED_MARKER, \"\", ...settings.indexingIgnorePatterns],\n });\n }\n }\n}\n","import { ResolvedProjectMetadata } from \"../projects/project-metadata-options\";\n\n/**\n * Default fallback placeholders for unresolved template variables.\n */\nconst FALLBACKS: Record<string, string> = {\n \"repository.owner\": \"<owner>\",\n \"repository.name\": \"<repo>\",\n \"repository.defaultBranch\": \"main\",\n \"organization.name\": \"<organization>\",\n \"organization.githubOrg\": \"<org>\",\n \"githubProject.name\": \"<project-name>\",\n \"githubProject.number\": \"<project-number>\",\n \"githubProject.nodeId\": \"<project-node-id>\",\n docsPath: \"<docs-path>\",\n};\n\n/** Matches `{{dotted.path}}` template variables. */\nconst TEMPLATE_RE = /\\{\\{(\\w+(?:\\.\\w+)*)\\}\\}/g;\n\n/**\n * Looks up a dotted path (e.g., \"repository.owner\") on a metadata object.\n * Returns the value as a string, or undefined if not found.\n */\nfunction getNestedValue(\n obj: Record<string, unknown>,\n path: string,\n): string | undefined {\n const parts = path.split(\".\");\n let current: unknown = obj;\n\n for (const part of parts) {\n if (current == null || typeof current !== \"object\") {\n return undefined;\n }\n current = (current as Record<string, unknown>)[part];\n }\n\n if (current == null) {\n return undefined;\n }\n\n return String(current);\n}\n\n/**\n * Result of template variable resolution.\n */\nexport interface TemplateResolveResult {\n /** The template string with all variables resolved or replaced with fallbacks. */\n readonly resolved: string;\n /** Template variable keys that could not be resolved from metadata. */\n readonly unresolvedKeys: ReadonlyArray<string>;\n}\n\n/**\n * Resolves `{{dotted.path}}` template variables in a string using project metadata.\n * Unresolved variables are replaced with their fallback placeholders.\n *\n * @param template - String potentially containing `{{variable}}` patterns\n * @param metadata - Resolved project metadata, or undefined if not available\n * @returns The resolved string and a list of any unresolved variable keys\n */\nexport function resolveTemplateVariables(\n template: string,\n metadata: ResolvedProjectMetadata | undefined,\n): TemplateResolveResult {\n if (!TEMPLATE_RE.test(template)) {\n return { resolved: template, unresolvedKeys: [] };\n }\n\n const unresolvedKeys: string[] = [];\n\n // Reset regex lastIndex since we used .test() above\n TEMPLATE_RE.lastIndex = 0;\n\n const resolved = template.replace(TEMPLATE_RE, (_match, key: string) => {\n if (metadata) {\n const value = getNestedValue(\n metadata as unknown as Record<string, unknown>,\n key,\n );\n if (value !== undefined) {\n return value;\n }\n }\n\n unresolvedKeys.push(key);\n return FALLBACKS[key] ?? `<${key}>`;\n });\n\n return { resolved, unresolvedKeys };\n}\n","import { Component } from \"projen\";\nimport { NodeProject } from \"projen/lib/javascript\";\nimport { TextFile } from \"projen/lib/textfile\";\nimport {\n AstroConfigOptions,\n AstroIntegrationSpec,\n} from \"./astro-config-options\";\n\n/**\n * Renders `astro.config.mjs` for an Astro project.\n */\nexport class AstroConfig extends Component {\n /**\n * Find the AstroConfig component on a project.\n */\n public static of(project: NodeProject): AstroConfig | undefined {\n const isAstroConfig = (c: Component): c is AstroConfig =>\n c instanceof AstroConfig;\n return project.components.find(isAstroConfig);\n }\n\n private readonly configFilePath: string;\n private readonly site?: string;\n private readonly base?: string;\n private readonly output?: string;\n private readonly integrations: Array<AstroIntegrationSpec>;\n private readonly adapter?: AstroIntegrationSpec;\n\n constructor(\n public readonly project: NodeProject,\n options: AstroConfigOptions = {},\n ) {\n super(project);\n\n this.configFilePath = \"astro.config.mjs\";\n this.site = options.site;\n this.base = options.base;\n this.output = options.output;\n this.integrations = options.integrations ?? [];\n this.adapter = options.adapter;\n\n this.synthesizeConfig();\n }\n\n /**\n * Render the config file contents as an array of lines.\n *\n * Exposed for unit testing — `synthesizeConfig` writes these to disk.\n */\n public renderConfig(): Array<string> {\n const imports: Array<string> = [\n 'import { defineConfig } from \"astro/config\";',\n ];\n const specs: Array<AstroIntegrationSpec> = [\n ...this.integrations,\n ...(this.adapter ? [this.adapter] : []),\n ];\n for (const spec of specs) {\n imports.push(renderImport(spec));\n }\n\n const body: Array<string> = [];\n if (this.site !== undefined) {\n body.push(` site: ${JSON.stringify(this.site)},`);\n }\n if (this.base !== undefined) {\n body.push(` base: ${JSON.stringify(this.base)},`);\n }\n if (this.output !== undefined) {\n body.push(` output: ${JSON.stringify(this.output)},`);\n }\n if (this.integrations.length > 0) {\n const calls = this.integrations.map(renderCall).join(\", \");\n body.push(` integrations: [${calls}],`);\n }\n if (this.adapter) {\n body.push(` adapter: ${renderCall(this.adapter)},`);\n }\n\n return [...imports, \"\", \"export default defineConfig({\", ...body, \"});\"];\n }\n\n private synthesizeConfig(): void {\n this.project.tryRemoveFile(this.configFilePath);\n new TextFile(this, this.configFilePath, {\n lines: this.renderConfig(),\n });\n }\n}\n\nfunction renderImport(spec: AstroIntegrationSpec): string {\n const asDefault = spec.defaultImport ?? true;\n const binding = asDefault ? spec.name : `{ ${spec.name} }`;\n return `import ${binding} from ${JSON.stringify(spec.importPath)};`;\n}\n\nfunction renderCall(spec: AstroIntegrationSpec): string {\n return `${spec.name}(${spec.args ?? \"\"})`;\n}\n","/**\n * Astro output mode.\n *\n * @see https://docs.astro.build/en/reference/configuration-reference/#output\n */\nexport const AstroOutput = {\n STATIC: \"static\",\n SERVER: \"server\",\n HYBRID: \"hybrid\",\n} as const;\n\nexport type AstroOutput = (typeof AstroOutput)[keyof typeof AstroOutput];\n\n/**\n * Declarative spec for an Astro integration or adapter import.\n *\n * Rendered into `astro.config.mjs` as an import plus an invocation in\n * the `integrations` array (or as the `adapter` field).\n */\nexport interface AstroIntegrationSpec {\n /**\n * Local binding used in the generated config, e.g. \"react\".\n */\n readonly name: string;\n\n /**\n * Module to import from, e.g. \"@astrojs/react\".\n */\n readonly importPath: string;\n\n /**\n * Raw argument expression passed to the integration call.\n *\n * Written verbatim inside the parentheses, e.g. `\"{ include: ['**\\/*.tsx'] }\"`.\n * When omitted the integration is invoked with no arguments.\n */\n readonly args?: string;\n\n /**\n * When true, use a default import (`import name from ...`).\n * When false or omitted, use a named import (`import { name } from ...`).\n *\n * @default true\n */\n readonly defaultImport?: boolean;\n}\n\n/**\n * Options controlling the rendered `astro.config.mjs`.\n */\nexport interface AstroConfigOptions {\n /**\n * Site URL (used for canonical URLs, sitemaps, RSS).\n */\n readonly site?: string;\n\n /**\n * Base path the site is deployed under.\n */\n readonly base?: string;\n\n /**\n * Output mode.\n *\n * @default AstroOutput.STATIC\n */\n readonly output?: AstroOutput;\n\n /**\n * Integrations rendered into the `integrations` array.\n */\n readonly integrations?: Array<AstroIntegrationSpec>;\n\n /**\n * SSR adapter rendered into the `adapter` field.\n */\n readonly adapter?: AstroIntegrationSpec;\n}\n","import { join, relative } from \"node:path\";\n// eslint-disable-next-line import/no-extraneous-dependencies\nimport { AWS_STAGE_TYPE } from \"@codedrifters/utils\";\nimport { Component } from \"projen\";\nimport { AwsCdkTypeScriptApp } from \"projen/lib/awscdk\";\nimport { AwsDeploymentTarget } from \"./aws-deployment-target\";\nimport { TurboRepo } from \"../turbo\";\n\n/*******************************************************************************\n *\n * AWS Deployment Configuration\n *\n * This component allows configuration of multiple AWS deployment\n * targets, each with its own account, region, and deployment type\n * (dev, stage, prod). It supports both local and CI deployments,\n * with customizable settings for each target.\n *\n ******************************************************************************/\n\n/*\nexport interface AwsDeploymentConfigOptions {}\n*/\n\nexport class AwsDeploymentConfig extends Component {\n public static of(\n project: AwsCdkTypeScriptApp,\n ): AwsDeploymentConfig | undefined {\n const isDefined = (c: Component): c is AwsDeploymentConfig =>\n c instanceof AwsDeploymentConfig;\n return project.components.find(isDefined);\n }\n\n /**\n * Environment variables to be injected into all tasks.\n */\n public readonly env: Record<string, string>;\n\n /**\n * The relative path to the project directory from the root of the project.\n */\n public readonly projectPath: string;\n\n /**\n * The relative path to the root of the project from the output directory.\n */\n public readonly rootPath: string;\n\n /**\n * The output directory for the CDK synthesis, from the root directory.\n */\n public readonly rootCdkOut: string;\n\n /**\n * The output directory for the CDK synthesis.\n */\n public readonly cdkOut: string;\n\n /**\n * Array of targets for deployment.\n */\n public readonly awsDeploymentTargets: Array<AwsDeploymentTarget> = [];\n\n constructor(project: AwsCdkTypeScriptApp) {\n super(project);\n\n /**\n * Common variables used across tasks.\n * Value must be exactly $(...) so Projen's task runtime expands it (evalEnvironment\n * only substitutes when the full value matches $(...)); the shell then expands\n * ${GIT_BRANCH_NAME:-$(git branch --show-current)} to the current branch or existing env.\n */\n this.env = {\n GIT_BRANCH_NAME:\n '$(echo \"${GIT_BRANCH_NAME:-$(git branch --show-current)}\")',\n };\n this.projectPath = relative(project.root.outdir, project.outdir);\n this.rootPath = relative(project.outdir, project.root.outdir);\n this.rootCdkOut = join(\"dist\", this.projectPath, \"cdk.out\");\n this.cdkOut = join(this.rootPath, \"dist\", this.projectPath, \"cdk.out\");\n\n /**\n * Reset some tasks we will rebuild below.\n */\n [\"deploy\", \"watch\"].forEach((taskName) => {\n const task = project.tasks.tryFind(taskName);\n if (task) {\n task.reset();\n task.say(\n \"Generic task is disabled. Please use the specific task for your deployment target.\",\n );\n }\n });\n\n /**\n * Redefine Synth here\n *\n * Deploy and watch get reconfigured per deployment target.\n * @see addDeploymentTarget()\n */\n this.configureSynthTask();\n }\n\n /*****************************************************************************\n *\n * Target filter helpers\n *\n * Return various targets for deployment scripts to use.\n *\n ****************************************************************************/\n\n /**\n * @returns All production deployment targets.\n */\n public get prodTargets(): Array<AwsDeploymentTarget> {\n return this.awsDeploymentTargets.filter(\n (target) => target.awsStageType === AWS_STAGE_TYPE.PROD,\n );\n }\n public get prodTargetsForCI(): Array<AwsDeploymentTarget> {\n return this.awsDeploymentTargets.filter(\n (target) =>\n target.awsStageType === AWS_STAGE_TYPE.PROD && target.ciDeployment,\n );\n }\n public get prodTargetsForLocal(): Array<AwsDeploymentTarget> {\n return this.awsDeploymentTargets.filter(\n (target) =>\n target.awsStageType === AWS_STAGE_TYPE.PROD && target.localDeployment,\n );\n }\n\n /**\n *\n * @returns All stage deployment targets.\n */\n public get stageTargets(): Array<AwsDeploymentTarget> {\n return this.awsDeploymentTargets.filter(\n (target) => target.awsStageType === AWS_STAGE_TYPE.STAGE,\n );\n }\n public get stageTargetsForCI(): Array<AwsDeploymentTarget> {\n return this.awsDeploymentTargets.filter(\n (target) =>\n target.awsStageType === AWS_STAGE_TYPE.STAGE && target.ciDeployment,\n );\n }\n public get stageTargetsForLocal(): Array<AwsDeploymentTarget> {\n return this.awsDeploymentTargets.filter(\n (target) =>\n target.awsStageType === AWS_STAGE_TYPE.STAGE && target.localDeployment,\n );\n }\n\n /**\n *\n * @returns All dev deployment targets.\n */\n public get devTargets(): Array<AwsDeploymentTarget> {\n return this.awsDeploymentTargets.filter(\n (target) => target.awsStageType === AWS_STAGE_TYPE.DEV,\n );\n }\n public get devTargetsForCI(): Array<AwsDeploymentTarget> {\n return this.awsDeploymentTargets.filter(\n (target) =>\n target.awsStageType === AWS_STAGE_TYPE.DEV && target.ciDeployment,\n );\n }\n public get devTargetsForLocal(): Array<AwsDeploymentTarget> {\n return this.awsDeploymentTargets.filter(\n (target) =>\n target.awsStageType === AWS_STAGE_TYPE.DEV && target.localDeployment,\n );\n }\n\n /*****************************************************************************\n *\n * Synth Tasks\n *\n * - Configure synth task to use the branch name\n * - Change the output location for easier workflows.\n *\n ****************************************************************************/\n\n private configureSynthTask = (): void => {\n this.project.tasks.tryFind(\"synth\")?.reset(`rm -rf ${this.cdkOut}`);\n this.project.tasks\n .tryFind(\"synth\")\n ?.exec(`cdk synth --output ${this.cdkOut}`, { env: this.env });\n\n this.project.tasks.tryFind(\"synth:silent\")?.reset(`rm -rf ${this.cdkOut}`);\n this.project.tasks\n .tryFind(\"synth:silent\")\n ?.exec(`cdk synth -q --output ${this.cdkOut}`, { env: this.env });\n };\n\n preSynthesize(): void {\n super.preSynthesize();\n\n /**\n * If turbo's active we should ensure the post compile task\n * is configured to consider the cdk output directory in it's root location.\n */\n if (TurboRepo.of(this.project)) {\n const turbo = TurboRepo.of(this.project)!;\n turbo.postCompileTask?.outputs.push(join(this.cdkOut, \"**\"));\n }\n }\n}\n","// eslint-disable-next-line import/no-extraneous-dependencies\nimport {\n AWS_STAGE_TYPE,\n AwsEnvironmentType,\n AwsStageType,\n DEPLOYMENT_TARGET_ROLE,\n DeploymentTargetRoleType,\n} from \"@codedrifters/utils\";\nimport { Component } from \"projen\";\nimport { AwsCdkTypeScriptApp } from \"projen/lib/awscdk\";\nimport { AwsDeploymentConfig } from \"./aws-deployment-config\";\nimport { GitBranch } from \"../git\";\n\n/*******************************************************************************\n *\n * AWS Deployment Configuration\n *\n * A single deployment target that CDK applications can be deployed into.\n *\n ******************************************************************************/\n\n/**\n * Represents the configuration for local deployment in AWS.\n */\nexport interface AwsLocalDeploymentConfig {\n /**\n * The AWS profile (in ~/.aws/config) to use for local deployment.\n *\n * @default generated dynamically based role name, account and region\n */\n readonly profile?: string;\n\n /**\n * Named Role used to conduct local deployments.\n *\n * @default \"poweruseraccess\"\n */\n readonly roleName?: string;\n\n /**\n * The pattern used to identify stacks to deploy in CI deployments.\n *\n * @default *-${account}-${region}\n */\n readonly stackPattern?: string;\n}\n\nexport interface CiDeploymentConfig {\n /**\n * The OIDC IAM Role to assume for CI deployments.\n */\n readonly roleArn: string;\n\n /**\n * The pattern used to identify stacks to deploy in CI deployments.\n *\n * @default *-${account}-${region}\n */\n readonly stackPattern?: string;\n}\n\n/**\n * Represents a deployment target in AWS, including account and region, and\n * branches allowed to deploy to this target.\n */\nexport interface AwsDeploymentTargetOptions {\n /**\n * The account name for the deployment target.\n */\n readonly account: string;\n\n /**\n * The AWS region for the deployment target.\n */\n readonly region: string;\n\n /**\n * AWS deployment type, such as dev, stage, or prod.\n *\n * @default 'dev'\n */\n readonly awsStageType?: AwsStageType;\n\n /**\n * Deployment target role: whether this (account, region) is the primary or\n * secondary deployment target (e.g. primary vs replica region).\n *\n * @default 'primary'\n */\n readonly deploymentTargetRole?: DeploymentTargetRoleType;\n\n /**\n * AWS environment type, such as primary or secondary.\n *\n * @deprecated Use `deploymentTargetRole` instead. This property is maintained for backward compatibility.\n * @default 'primary'\n */\n readonly awsEnvironmentType?: AwsEnvironmentType;\n\n /**\n * The AWS profile to use for this deployment target.\n *\n * @default ['main'] when prod release type, ['feature/*'] when dev type\n */\n readonly branches?: Array<GitBranch>;\n\n /**\n * Can this deployment target be used for local development?\n *\n * @default true for dev environments, false for prod environments\n */\n readonly localDeployment?: boolean;\n\n /**\n * Configuration when deploying to this target locally.\n */\n readonly localDeploymentConfig?: AwsLocalDeploymentConfig;\n\n /**\n * Can this deployment target be used in CI deployments?\n *\n * @default false\n */\n readonly ciDeployment?: boolean;\n\n /*\n * Configuration when deploying to this target in CI.\n\n */\n readonly ciDeploymentConfig?: CiDeploymentConfig;\n}\n\nexport class AwsDeploymentTarget extends Component {\n /**\n * Static method to discovert targets in a project.\n */\n public static of(\n project: AwsCdkTypeScriptApp,\n ): Array<AwsDeploymentTarget> | undefined {\n const isDefined = (c: Component): c is AwsDeploymentTarget =>\n c instanceof AwsDeploymentTarget;\n return project.components.filter(isDefined);\n }\n\n /**\n * The account name for the deployment target.\n */\n public account: string;\n\n /**\n * The AWS region for the deployment target.\n */\n public region: string;\n\n /**'\n * AWS stage type, such as dev, stage, or prod.\n *\n * @default 'dev'\n */\n public awsStageType: AwsStageType;\n\n /**\n * Deployment target role: whether this (account, region) is the primary or\n * secondary deployment target (e.g. primary vs replica region).\n *\n * @default 'primary'\n */\n public deploymentTargetRole: DeploymentTargetRoleType;\n\n /**\n * AWS environment type, such as primary or secondary.\n *\n * @deprecated Use `deploymentTargetRole` instead. This property is maintained for backward compatibility.\n * @default 'primary'\n */\n public awsEnvironmentType: AwsEnvironmentType;\n\n /**\n * The AWS profile to use for this deployment target.\n *\n * @default ['main'] when prod release type, ['feature/*'] when dev type\n */\n public branches: Array<GitBranch> = [];\n\n /**\n * Can this deployment target be used for local development?\n *\n * @default true for dev environments, false for prod environments\n */\n public localDeployment?: boolean;\n\n /**\n * Configuration when deploying to this target locally.\n */\n public localDeploymentConfig?: AwsLocalDeploymentConfig;\n\n /**\n * Can this deployment target be used in CI deployments?\n *\n * @default false\n */\n public ciDeployment?: boolean;\n\n /*\n * Configuration when deploying to this target in CI.\n */\n public ciDeploymentConfig?: Required<CiDeploymentConfig>;\n\n /**\n * Configuration for the CDK output directory for this deployment target.\n */\n public awsDeploymentConfig: AwsDeploymentConfig;\n\n constructor(\n project: AwsCdkTypeScriptApp,\n options: AwsDeploymentTargetOptions,\n ) {\n super(project);\n\n /**\n * Set target region and account.\n */\n this.account = options.account;\n this.region = options.region;\n\n /**\n * Set default type\n */\n this.awsStageType = options.awsStageType || AWS_STAGE_TYPE.DEV;\n\n /**\n * Set deployment target role (preferred) or fall back to deprecated awsEnvironmentType.\n */\n const role =\n options.deploymentTargetRole ??\n options.awsEnvironmentType ??\n DEPLOYMENT_TARGET_ROLE.PRIMARY;\n this.deploymentTargetRole = role;\n this.awsEnvironmentType = role;\n\n /**\n * Set default Branches\n */\n\n this.branches =\n options.branches ??\n (this.awsStageType === AWS_STAGE_TYPE.PROD\n ? [\n {\n branch: \"main\",\n },\n ]\n : [\n {\n branch: \"feature/*\",\n },\n ]);\n\n /**\n * Set default for local deployment\n */\n this.localDeployment =\n options.localDeployment ?? this.awsStageType === AWS_STAGE_TYPE.DEV;\n\n /**\n * Some default configurations for local deployments.\n */\n if (this.localDeployment) {\n const roleName =\n options.localDeploymentConfig?.roleName?.toLowerCase() ||\n \"poweruseraccess\";\n const profile =\n options.localDeploymentConfig?.profile ||\n `${roleName}-${this.awsStageType}-${this.account}-${this.region}`;\n\n const stackPattern =\n options.localDeploymentConfig?.stackPattern ||\n `${this.awsStageType}/${this.awsEnvironmentType}/*-${this.account}-${this.region}`;\n\n this.localDeploymentConfig = {\n profile,\n roleName,\n stackPattern,\n ...options.localDeploymentConfig,\n };\n }\n\n /**\n * Set CI deployment default\n */\n this.ciDeployment = options.ciDeployment ?? false;\n\n /**\n * Some defaults for CI deployments.\n */\n if (this.ciDeployment) {\n const roleArn =\n options.ciDeploymentConfig?.roleArn ||\n `arn:aws:iam::${this.account}:role/GitHubDeployer}`;\n\n const stackPattern =\n options.ciDeploymentConfig?.stackPattern ||\n `${this.awsStageType}/${this.awsEnvironmentType}/*-${this.account}-${this.region}`;\n\n this.ciDeploymentConfig = {\n roleArn,\n stackPattern,\n ...options.ciDeploymentConfig,\n };\n }\n\n /**\n * Find or create CDK folder config for this project.\n */\n this.awsDeploymentConfig =\n AwsDeploymentConfig.of(project) || new AwsDeploymentConfig(project);\n\n /**\n * Add the target to the deployment targets array.\n */\n this.awsDeploymentConfig.awsDeploymentTargets.push(this);\n\n // Deploy tasks are configured per target.\n this.configureDeployTask();\n\n // Watch tasks are configured per target.\n this.configureWatchTask();\n }\n\n /*****************************************************************************\n *\n * Deploy Tasks\n *\n * - If local deploy, add a deploy task.\n *\n ****************************************************************************/\n\n private configureDeployTask = (): void => {\n if (this.localDeployment) {\n const taskName = [\n \"deploy\",\n this.awsStageType,\n this.account,\n this.region,\n ].join(\":\");\n const deployTask = this.project.tasks.addTask(taskName, {\n env: this.awsDeploymentConfig.env,\n });\n deployTask.exec(\n `cdk deploy --lookups=false --require-approval=never --profile=${this.localDeploymentConfig?.profile} --app=${this.awsDeploymentConfig.cdkOut} \"${this.localDeploymentConfig?.stackPattern}\"`,\n );\n }\n };\n\n /*****************************************************************************\n *\n * Watch tasks\n *\n * - Configure watch task to use the branch name\n * - configure watch task to use the correct synth output location.\n *\n ****************************************************************************/\n\n private configureWatchTask = (): void => {\n if (this.localDeployment) {\n const taskName = [\n \"watch\",\n this.awsStageType,\n this.account,\n this.region,\n ].join(\":\");\n const watchTask = this.project.tasks.addTask(taskName, {\n env: this.awsDeploymentConfig.env,\n });\n\n // update the synth first\n const synthSilent = this.project.tasks.tryFind(\"synth:silent\");\n if (synthSilent) {\n watchTask.spawn(synthSilent);\n }\n\n // do a normal deploy\n watchTask.exec(\n `cdk deploy --lookups=false --require-approval=never --profile=${this.localDeploymentConfig?.profile} --app=${this.awsDeploymentConfig.cdkOut} \"${this.localDeploymentConfig?.stackPattern}\"`,\n );\n\n // watch for changes and log output\n watchTask.exec(\n `cdk watch --lookups=false --require-approval=never --hotswap --profile=${this.localDeploymentConfig?.profile} \"${this.localDeploymentConfig?.stackPattern}\"`,\n );\n }\n };\n}\n","const NPM_REGISTRY = \"https://registry.npmjs.org\";\n\n/**\n * Metadata for a package from the npm registry. Only the fields we use are typed.\n *\n * @see https://github.com/npm/registry/blob/master/docs/responses/package-metadata.md\n */\ninterface NpmPackageMetadata {\n name?: string;\n \"dist-tags\"?: { latest?: string };\n time?: Record<string, string>;\n versions?: Record<string, unknown>;\n}\n\n/**\n * Returns true if the version has a semver prerelease segment (e.g. -canary, -alpha, -beta).\n * Full releases like 1.2.3 or 1.2.3+build.1 return false.\n */\nfunction isPrerelease(version: string): boolean {\n const v = version.replace(/^v/, \"\");\n return /^\\d+\\.\\d+\\.\\d+-/.test(v);\n}\n\n/**\n * Compares two semver-like version strings (e.g. \"1.2.3\").\n * Returns negative if a < b, positive if a > b, 0 if equal.\n * Prerelease segments are treated as less than release.\n */\nfunction compareVersions(a: string, b: string): number {\n const parse = (v: string): number[] => {\n const parts = v.replace(/^v/, \"\").split(/[-+]/)[0].split(\".\");\n return parts.map((p) => {\n const n = parseInt(p, 10);\n return Number.isNaN(n) ? 0 : n;\n });\n };\n const pa = parse(a);\n const pb = parse(b);\n const len = Math.max(pa.length, pb.length);\n for (let i = 0; i < len; i++) {\n const na = pa[i] ?? 0;\n const nb = pb[i] ?? 0;\n if (na !== nb) return na - nb;\n }\n return 0;\n}\n\n/**\n * Returns the latest full-release version of an npm package that has been\n * published for at least `minimumReleaseAgeMinutes` minutes. Prefers the\n * version indicated by the registry's \"latest\" dist-tag when it is a full\n * release: if that version's publish time is in the registry and old enough,\n * it is used; if it is not in the registry's \"time\" object (e.g. truncated\n * for large packages), the dist-tag is still used so npm's \"latest\" is\n * followed. When the dist-tag version is too new (in time but not old enough),\n * we fall back to the highest full-release version that is old enough and\n * ≤ latest (e.g. latest 2.x that's old enough, not 3.0.0). Prerelease\n * versions are excluded. Returns null if `time` is missing or no version is\n * eligible.\n *\n * @param packageName - npm package name (e.g. \"projen\").\n * @param minimumReleaseAgeMinutes - minimum age in minutes (e.g. 1440 for 24h).\n * @returns The latest eligible version string, or null.\n */\nexport async function getLatestEligibleVersion(\n packageName: string,\n minimumReleaseAgeMinutes: number,\n): Promise<string | null> {\n const url = `${NPM_REGISTRY}/${encodeURIComponent(packageName)}`;\n let res: Response;\n try {\n res = await fetch(url, {\n headers: { Accept: \"application/json\" },\n });\n } catch {\n return null;\n }\n if (!res.ok) return null;\n let data: NpmPackageMetadata;\n try {\n data = (await res.json()) as NpmPackageMetadata;\n } catch {\n return null;\n }\n const time = data.time;\n if (!time || typeof time !== \"object\") return null;\n\n const nowMs = Date.now();\n const minAgeMs = minimumReleaseAgeMinutes * 60 * 1000;\n\n const distTagLatest = data[\"dist-tags\"]?.latest;\n if (distTagLatest && !isPrerelease(distTagLatest)) {\n const publishedAtStr = time[distTagLatest];\n if (typeof publishedAtStr === \"string\") {\n const publishedAt = Date.parse(publishedAtStr);\n if (!Number.isNaN(publishedAt) && nowMs - publishedAt >= minAgeMs) {\n return distTagLatest;\n }\n } else {\n return distTagLatest;\n }\n }\n\n const versionTimestamps: { version: string; publishedAt: number }[] = [];\n for (const [key, value] of Object.entries(time)) {\n if (key === \"created\" || key === \"modified\" || typeof value !== \"string\") {\n continue;\n }\n if (isPrerelease(key)) continue;\n const publishedAt = Date.parse(value);\n if (Number.isNaN(publishedAt)) continue;\n const ageMs = nowMs - publishedAt;\n if (ageMs >= minAgeMs) {\n versionTimestamps.push({ version: key, publishedAt });\n }\n }\n\n if (versionTimestamps.length === 0) return null;\n\n let candidates = versionTimestamps;\n if (distTagLatest && !isPrerelease(distTagLatest)) {\n candidates = versionTimestamps.filter(\n (e) => compareVersions(e.version, distTagLatest) <= 0,\n );\n }\n if (candidates.length === 0) return null;\n\n candidates.sort((a, b) => compareVersions(b.version, a.version));\n return candidates[0].version;\n}\n","import { VERSION } from \"./versions\";\n\n/**\n * Keys of the VERSION object in versions.ts.\n */\nexport type VersionKey = keyof typeof VERSION;\n\n/**\n * Mapping of VERSION keys that are backed by an npm package and eligible\n * for auto-update. Only these keys should be updated by version-update\n * automation; others (e.g. NODE_WORKFLOWS) are skipped.\n *\n * @see {@link VERSION_KEYS_SKIP} for keys that must not be auto-updated.\n */\nexport const VERSION_NPM_PACKAGES: ReadonlyArray<{\n key: VersionKey;\n npmPackage: string;\n}> = [\n { key: \"ASTRO_VERSION\", npmPackage: \"astro\" },\n { key: \"AWS_CDK_CLI_VERSION\", npmPackage: \"aws-cdk\" },\n { key: \"AWS_CDK_LIB_VERSION\", npmPackage: \"aws-cdk-lib\" },\n { key: \"AWS_CONSTRUCTS_VERSION\", npmPackage: \"constructs\" },\n { key: \"PNPM_VERSION\", npmPackage: \"pnpm\" },\n { key: \"PROJEN_VERSION\", npmPackage: \"projen\" },\n { key: \"SHARP_VERSION\", npmPackage: \"sharp\" },\n { key: \"STARLIGHT_VERSION\", npmPackage: \"@astrojs/starlight\" },\n { key: \"TURBO_VERSION\", npmPackage: \"turbo\" },\n { key: \"TYPES_NODE_VERSION\", npmPackage: \"@types/node\" },\n { key: \"VITEST_VERSION\", npmPackage: \"vitest\" },\n] as const;\n\n/**\n * VERSION keys that are not backed by npm or must be skipped by\n * auto-update (e.g. runtime versions like Node.js, or pinned deps like\n * VITE_VERSION until ESM-only test setup).\n */\nexport const VERSION_KEYS_SKIP: ReadonlyArray<VersionKey> = [\n \"NODE_WORKFLOWS\",\n \"VITE_VERSION\",\n \"VITEST_VERSION\", // Pinned to 3.x for Vite 5 compatibility; skip until ESM-only (issue #142)\n];\n","import * as spec from \"@jsii/spec\";\nimport { Component, JsonFile } from \"projen\";\nimport { TypeScriptProject } from \"projen/lib/typescript\";\nimport { ValueOf } from \"type-fest\";\n\n/**\n * The FQNs for the base classes and options used by Jsii.\n *\n * These are the defaults used by Projen's TypeScriptProject.\n */\nconst ProjenBaseFqn = {\n TYPESCRIPT_PROJECT: \"projen.typescript.TypeScriptProject\",\n TYPESCRIPT_PROJECT_OPTIONS: \"projen.typescript.TypeScriptProjectOptions\",\n} as const;\n\nexport interface ClassTypeOptions {\n /**\n * The name of the class.\n *\n * @example \"MyProject\"\n */\n name: string;\n\n /**\n * The FQN for the base class this class is extending.\n *\n * @default ProjenBaseFqn.TYPESCRIPT_PROJECT\n */\n baseFqn?: ValueOf<typeof ProjenBaseFqn> | string;\n\n /**\n * The FQN for the options for this class.\n *\n * @default ProjenBaseFqn.TYPESCRIPT_PROJECT_OPTIONS\n */\n optionsFqn?: ValueOf<typeof ProjenBaseFqn> | string;\n}\n\nexport class JsiiFaker extends Component {\n // find project singleton\n public static of(project: TypeScriptProject): JsiiFaker | undefined {\n const isDefined = (c: Component): c is JsiiFaker => c instanceof JsiiFaker;\n return project.components.find(isDefined);\n }\n\n private _assemblyName: string;\n private _types: { [name: string]: spec.Type } = {};\n\n constructor(public readonly project: TypeScriptProject) {\n super(project);\n\n /**\n * In JSII, the assembly name is essentially the package name. It's used as a\n * scope when targeting types and metadata in other \"jsii assemblies\" that\n * might be in sub-packages used by the project.\n *\n * For this case, we'll just use the package name from Projen.\n */\n this._assemblyName = this.project.package.packageName;\n\n new JsonFile(project, \".jsii\", {\n obj: () => {\n return {\n name: this._assemblyName,\n types: this._types,\n };\n },\n });\n }\n\n public toJSON = () => {\n return {\n types: this._types,\n };\n };\n\n public addClassType(options: ClassTypeOptions) {\n const fqn = [this._assemblyName, options.name].join(\".\");\n const type: spec.ClassType = {\n assembly: this._assemblyName,\n base: options.baseFqn ?? ProjenBaseFqn.TYPESCRIPT_PROJECT,\n fqn,\n kind: spec.TypeKind.Class,\n name: options.name,\n initializer: {\n parameters: [\n {\n name: \"options\",\n type: {\n fqn:\n options.optionsFqn ?? ProjenBaseFqn.TYPESCRIPT_PROJECT_OPTIONS,\n },\n },\n ],\n },\n };\n\n this._types[fqn] = type;\n }\n}\n","import { SampleFile } from \"projen\";\nimport { AstroConfig } from \"../astro/astro-config\";\nimport {\n AstroConfigOptions,\n AstroIntegrationSpec,\n} from \"../astro/astro-config-options\";\nimport { TurboRepo } from \"../turbo\";\nimport { VERSION } from \"../versions\";\nimport {\n TestRunner,\n TypeScriptProject,\n TypeScriptProjectOptions,\n} from \"./typescript-project\";\n\n/**\n * Configuration options for AstroProject.\n */\nexport interface AstroProjectOptions\n extends TypeScriptProjectOptions, AstroConfigOptions {\n /**\n * Astro package version.\n *\n * @default VERSION.ASTRO_VERSION\n */\n readonly astroVersion?: string;\n\n /**\n * Emit sample Astro starter files (`src/pages/index.astro`, `public/favicon.svg`).\n *\n * @default false\n */\n readonly sampleCode?: boolean;\n\n /**\n * Astro tsconfig preset to extend.\n *\n * @default \"astro/tsconfigs/strict\"\n */\n readonly astroTsconfigExtends?: string;\n}\n\n/**\n * Minimal Astro site scaffolded on top of {@link TypeScriptProject}.\n *\n * Replaces the `tsc` compile step with `astro check && astro build`, writes\n * `astro.config.mjs`, sets `\"type\": \"module\"`, and wires dev/preview tasks.\n */\nexport class AstroProject extends TypeScriptProject {\n /**\n * Rendered Astro config component.\n */\n public readonly astroConfig: AstroConfig;\n\n constructor(userOptions: AstroProjectOptions) {\n /**\n * Default to Vitest — Astro's native test runner — and exclude `astro`\n * from projen's per-package ncu upgrade workflow so only the\n * configulator VERSION-driven update path owns it.\n */\n const options: AstroProjectOptions = {\n testRunner: TestRunner.VITEST,\n ...userOptions,\n depsUpgradeOptions: {\n ...userOptions.depsUpgradeOptions,\n exclude: [...(userOptions.depsUpgradeOptions?.exclude ?? []), \"astro\"],\n },\n };\n\n super(options);\n\n const astroVersion = options.astroVersion ?? VERSION.ASTRO_VERSION;\n const astroTsconfigExtends =\n options.astroTsconfigExtends ?? \"astro/tsconfigs/strict\";\n\n /**\n * Astro ships as ESM; the site package must be a module.\n */\n this.package.addField(\"type\", \"module\");\n\n /**\n * Extend Astro's tsconfig preset so `astro check` and IDE tooling\n * understand `.astro` files, JSX, and bundler-style resolution.\n */\n this.tsconfig?.file.addOverride(\"extends\", astroTsconfigExtends);\n this.tsconfig?.addInclude(\".astro/types.d.ts\");\n this.tsconfig?.addInclude(\"src/**/*.astro\");\n\n /**\n * Replace projen's tsc-driven compile with Astro's build pipeline.\n */\n this.compileTask.reset();\n this.compileTask.exec(\"astro check\");\n this.compileTask.exec(\"astro build\");\n\n /**\n * Point `watch` at Astro's dev server (projen's default runs `tsc -w`,\n * which is meaningless for an Astro site).\n */\n this.tasks.tryFind(\"watch\")?.reset(\"astro dev\");\n\n /**\n * A website is not an npm tarball — reset `package` to a no-op so the\n * inherited `build` task does not emit `dist/js/*.tgz` alongside the\n * actual site output.\n */\n this.packageTask.reset();\n\n /**\n * Astro CLI tasks. `build` already exists on projen; add only the\n * Astro-specific lifecycle tasks.\n */\n if (!this.tasks.tryFind(\"dev\")) {\n this.addTask(\"dev\", {\n description: \"Start the Astro dev server\",\n exec: \"astro dev\",\n receiveArgs: true,\n });\n }\n if (!this.tasks.tryFind(\"preview\")) {\n this.addTask(\"preview\", {\n description: \"Preview the built site locally\",\n exec: \"astro preview\",\n receiveArgs: true,\n });\n }\n if (!this.tasks.tryFind(\"check\")) {\n this.addTask(\"check\", {\n description: \"Run Astro's type and content checks\",\n exec: \"astro check\",\n });\n }\n\n /**\n * Runtime and tooling dependencies.\n */\n this.addDeps(`astro@${astroVersion}`);\n this.addDevDeps(\n \"@astrojs/check\",\n \"astro-eslint-parser\",\n \"eslint-plugin-astro\",\n \"prettier-plugin-astro\",\n );\n\n /**\n * Register the Astro prettier plugin so `.astro` files are formatted.\n */\n const prettierConfig = this.tryFindObjectFile(\".prettierrc.json\");\n prettierConfig?.addOverride(\"plugins\", [\"prettier-plugin-astro\"]);\n prettierConfig?.addOverride(\"overrides\", [\n { files: \"*.astro\", options: { parser: \"astro\" } },\n ]);\n\n /**\n * Wire eslint-plugin-astro so `.astro` files are actually linted.\n * Projen's default `fileExtensions` is constructor-only and set to `.ts`,\n * so we add an explicit lint pattern to force `.astro` paths onto the\n * generated eslint command line.\n */\n this.eslint?.addPlugins(\"astro\");\n this.eslint?.addExtends(\"plugin:astro/recommended\");\n this.eslint?.addOverride({\n files: [\"*.astro\"],\n parser: \"astro-eslint-parser\",\n });\n this.eslint?.addLintPattern(\"src/**/*.astro\");\n\n /**\n * Astro-specific gitignore entries. `dist` is already handled by the\n * base TypeScriptProject.\n */\n this.gitignore.addPatterns(\".astro\", \".vercel\", \".netlify\");\n\n /**\n * Extend turbo inputs so the compile task invalidates on Astro-specific\n * source paths. Outputs (`dist/**`) are already added by the base class.\n */\n const turbo = TurboRepo.of(this);\n if (turbo?.compileTask) {\n turbo.compileTask.inputs.push(\"public/**\", \"astro.config.mjs\");\n }\n\n /**\n * Render astro.config.mjs.\n */\n const integrations: Array<AstroIntegrationSpec> =\n options.integrations ?? [];\n this.astroConfig = new AstroConfig(this, {\n site: options.site,\n base: options.base,\n output: options.output,\n integrations,\n adapter: options.adapter,\n });\n\n /**\n * Optional starter files.\n */\n if (options.sampleCode === true) {\n new SampleFile(this, \"src/pages/index.astro\", {\n contents: DEFAULT_INDEX_ASTRO,\n });\n new SampleFile(this, \"public/favicon.svg\", {\n contents: DEFAULT_FAVICON_SVG,\n });\n }\n }\n}\n\nconst DEFAULT_INDEX_ASTRO = `---\n// Welcome to Astro!\n---\n<html lang=\"en\">\n <head>\n <meta charset=\"utf-8\" />\n <link rel=\"icon\" type=\"image/svg+xml\" href=\"/favicon.svg\" />\n <meta name=\"viewport\" content=\"width=device-width\" />\n <title>Astro</title>\n </head>\n <body>\n <h1>Hello, Astro!</h1>\n </body>\n</html>\n`;\n\nconst DEFAULT_FAVICON_SVG = `<svg xmlns=\"http://www.w3.org/2000/svg\" viewBox=\"0 0 128 128\"><path d=\"M64 8a56 56 0 1 0 0 112A56 56 0 0 0 64 8Z\" fill=\"#ff5d01\"/></svg>\n`;\n","import { typescript } from \"projen\";\nimport {\n NodePackageManager,\n Transform,\n UpgradeDependenciesSchedule,\n} from \"projen/lib/javascript\";\nimport { ReleaseTrigger } from \"projen/lib/release\";\nimport { merge } from \"ts-deepmerge\";\nimport { MonorepoProject } from \"./monorepo-project\";\nimport { AgentConfig } from \"../agent/agent-config\";\nimport { AgentConfigOptions } from \"../agent/agent-config-options\";\nimport { PnpmWorkspace } from \"../pnpm\";\nimport { ResetTask, ResetTaskOptions } from \"../tasks/reset-task\";\nimport { TurboRepo } from \"../turbo\";\nimport { Vitest, VitestOptions } from \"../vitest\";\n\n/**\n * Test runner for TypeScript projects.\n */\nexport const TestRunner = {\n JEST: \"jest\",\n VITEST: \"vitest\",\n} as const;\n\nexport type TestRunner = (typeof TestRunner)[keyof typeof TestRunner];\n\n/**\n * Configuration options for TypeScriptProject.\n */\nexport interface TypeScriptProjectOptions extends Omit<\n typescript.TypeScriptProjectOptions,\n \"defaultReleaseBranch\"\n> {\n /**\n * Test runner to use.\n *\n * @default TestRunner.JEST\n */\n readonly testRunner?: TestRunner;\n\n /**\n * Options for Vitest (only used when testRunner is 'vitest').\n */\n readonly vitestOptions?: VitestOptions;\n\n /**\n * Enable the reset task that deletes all build artifacts.\n *\n * @default true\n */\n readonly resetTask?: boolean;\n\n /**\n * Options for the reset task.\n */\n readonly resetTaskOptions?: ResetTaskOptions;\n\n /**\n * AI agent configuration (Cursor, Claude Code rules).\n * Generates rule files with auto-detected bundles based on project tooling.\n *\n * - `true` or `{}`: enable with auto-detected defaults\n * - `AgentConfigOptions`: enable with explicit configuration\n * - `false` or `undefined`: disabled (default)\n *\n * Sub-projects do not inherit `AgentConfig` from their parent\n * `MonorepoProject`. Agent rule files are rendered only on projects that\n * explicitly opt in, so a monorepo's root `AgentConfig` does not duplicate\n * `.cursor/`, `.claude/`, or `CLAUDE.md` into each sub-project's `outdir`.\n *\n * @default false\n */\n readonly agentConfig?: AgentConfigOptions | boolean;\n}\n\nexport class TypeScriptProject extends typescript.TypeScriptProject {\n constructor(userOptions: TypeScriptProjectOptions) {\n /**\n * Configulator requires every project to live inside a MonorepoProject.\n * The catalog-based @types/node pin and the workspace install hook both\n * assume the parent exists.\n */\n if (!(userOptions.parent instanceof MonorepoProject)) {\n throw new Error(\n \"TypeScriptProject must be parented to a MonorepoProject. Pass `parent: <MonorepoProject>` in the project options.\",\n );\n }\n\n const parent = userOptions.parent;\n const pnpmVersion = parent.pnpmVersion;\n const pnpmWorkspace = PnpmWorkspace.of(parent);\n\n /*************************************************************************\n *\n * Default Options\n *\n ************************************************************************/\n\n const testRunner = userOptions.testRunner ?? TestRunner.JEST;\n const useJest = testRunner === TestRunner.JEST;\n\n const defaultOptions: Omit<TypeScriptProjectOptions, \"name\"> & {\n defaultReleaseBranch: string;\n } = {\n /**\n * This is a standard, so don't require it to passed in everywhere.\n */\n defaultReleaseBranch: \"main\",\n\n /**\n * Enable reset task by default.\n */\n resetTask: true,\n\n /**\n * Packaging options\n */\n packageManager: NodePackageManager.PNPM,\n pnpmVersion: pnpmVersion,\n licensed: userOptions.license !== undefined || false,\n copyrightOwner: \"CodeDrifters\",\n release: false,\n\n /**\n * Don't add sample code.\n */\n sampleCode: false,\n\n ...(useJest\n ? {\n /**\n * Make sure jest config is stored outside of package.json\n */\n jestOptions: {\n configFilePath: \"jest.config.json\",\n jestConfig: {\n roots: [`<rootDir>/src`],\n transform: {\n [\"^.+\\\\.[t]sx?$\"]: new Transform(\"@swc/jest\"),\n },\n moduleFileExtensions: [\"js\", \"ts\"],\n },\n },\n /**\n * SWC for faster testing\n */\n devDeps: [\"@swc/jest\", \"@swc/core\"] as string[],\n }\n : {\n jest: false,\n devDeps: [] as string[],\n }),\n\n /**\n * Turn on prettier formatting\n */\n prettier: true,\n\n /**\n * Don't package test files.\n */\n npmIgnoreOptions: {\n ignorePatterns: [\"*.spec.*\", \"*.test.*\"],\n },\n\n /**\n * Options for the automated dependency upgrade task / workflow\n * Automatically exclude any packages that are managed by the root\n * project as default catalog dependencies since we want to let the\n * catalog manage those dependencies.\n */\n depsUpgrade: true,\n depsUpgradeOptions: {\n workflow: false,\n exclude: Object.keys(pnpmWorkspace?.defaultCatalog || {}),\n ...(userOptions.parent && userOptions.parent instanceof MonorepoProject\n ? {\n workflowOptions: {\n schedule: UpgradeDependenciesSchedule.WEEKLY,\n },\n cooldown: 1,\n }\n : {}),\n },\n\n /**\n * Only release when the package folder source content or package.json\n * (version, dependencies) changes.\n */\n releaseTrigger: ReleaseTrigger.continuous({\n paths: [\n `${userOptions.outdir}/src/**`,\n `${userOptions.outdir}/package.json`,\n ],\n }),\n };\n\n /*************************************************************************\n *\n * Merge defaults into user options\n *\n ************************************************************************/\n\n const options: TypeScriptProjectOptions &\n typescript.TypeScriptProjectOptions = merge(defaultOptions, userOptions);\n\n super(options);\n\n /**\n * Use catalog version for @types/node so all packages share a single\n * pinned version (overrides projen's default @types/node@*).\n */\n this.addDevDeps(\"@types/node@catalog:\");\n\n /**\n * Exclude test files from the main tsconfig only (not tsconfig.dev) so\n * tsc --build compiles only library code (avoids pulling in test-runner\n * types e.g. Vitest/Vite). ESLint and tests still use tsconfig.dev which\n * includes test files.\n */\n this.tsconfig?.addExclude(\"**/*.test.*\");\n this.tsconfig?.addExclude(\"**/*.spec.*\");\n\n /**\n * When using Jest, remove ts-jest since we use @swc/jest.\n * When using Vitest, add the Vitest component (test task + config + deps).\n */\n if (options.testRunner === TestRunner.VITEST) {\n new Vitest(this, {\n config: {\n include: [\"src/**/*.{test,spec}.?(c|m)[jt]s?(x)\"],\n ...options.vitestOptions?.config,\n },\n ...options.vitestOptions,\n });\n } else {\n this.deps.removeDependency(\"ts-jest\");\n }\n\n /**\n * Specify package manager\n */\n this.package.file.addOverride(\n \"packageManager\",\n `pnpm@${options.pnpmVersion}`,\n );\n\n /**\n *\n * Disable this rule for all test files.\n *\n * Unless we turn this off, ESLint will suggest that anything found in a test\n * needs to be a dep instead of a devDep. Projen actually already turns off\n * the rule for files in the tests/* folder but since we commonly put tests\n * next to the code it's testing, we need to do this ourselves.\n *\n */\n this.eslint?.addOverride({\n files: [\"**/*.test.*\", \"**/*.spec.*\"],\n rules: {\n \"import/no-extraneous-dependencies\": \"off\",\n },\n });\n\n /**\n * Some standard ignores for all projects.\n */\n this.gitignore?.addPatterns(\".DS_Store\", \"test-reports\");\n this.npmignore?.addPatterns(\"*.spec.*\", \"*.test.*\", \"__fixtures__\");\n\n /**\n * If turbo is active in the parent project, configure it here.\n */\n const turboActive =\n userOptions.parent && TurboRepo.of(userOptions.parent) !== undefined;\n if (turboActive) {\n const turbo = new TurboRepo(this);\n turbo.compileTask?.outputs.push(\"dist/**\");\n turbo.compileTask?.outputs.push(\"lib/**\");\n //turbo.testTask?.inputs.push(\"src/**\");\n }\n\n /**\n * AI agent configuration — opt-in per project. Does not propagate from\n * parent MonorepoProject, so sub-projects don't render duplicate\n * `.cursor/` / `.claude/` / `CLAUDE.md` files into their own outdir.\n */\n if (\n options.agentConfig === true ||\n typeof options.agentConfig === \"object\"\n ) {\n new AgentConfig(\n this,\n typeof options.agentConfig === \"object\" ? options.agentConfig : {},\n );\n }\n\n /**\n * Add reset task if enabled.\n */\n if (options.resetTask !== false) {\n const defaultResetTaskOptions: ResetTaskOptions = {\n pathsToRemove: [\n \"node_modules\",\n \"dist\",\n \"lib\",\n \"coverage\",\n \"test-reports\",\n \".turbo\",\n \"tsconfig.tsbuildinfo\",\n this.artifactsDirectory,\n ],\n };\n const userResetTaskOptions = options.resetTaskOptions ?? {};\n const resetTaskOptions: ResetTaskOptions = merge(\n defaultResetTaskOptions,\n {\n ...userResetTaskOptions,\n pathsToRemove: [\n ...(defaultResetTaskOptions.pathsToRemove ?? []),\n ...(userResetTaskOptions.pathsToRemove ?? []),\n ],\n },\n );\n new ResetTask(this, resetTaskOptions);\n }\n\n /**\n *\n */\n\n if (options.parent && options.parent instanceof MonorepoProject) {\n // Install dependencies via the parent project\n /* @ts-ignore access private method */\n const originalResolve = this.package.resolveDepsAndWritePackageJson;\n /* @ts-ignore access private method */\n this.package.installDependencies = () => {\n (options.parent as MonorepoProject).requestInstallDependencies({\n resolveDepsAndWritePackageJson: () =>\n originalResolve.apply(this.package),\n });\n };\n /* @ts-ignore access private method */\n this.package.resolveDepsAndWritePackageJson = () => {};\n }\n }\n}\n","import { BuildWorkflowOptions } from \"projen/lib/build\";\nimport { WorkflowSteps } from \"projen/lib/github\";\nimport {\n NodePackageManager,\n UpgradeDependenciesSchedule,\n} from \"projen/lib/javascript\";\nimport {\n TypeScriptAppProject,\n TypeScriptProjectOptions,\n} from \"projen/lib/typescript\";\nimport { merge } from \"ts-deepmerge\";\nimport { ProjectMetadata } from \"./project-metadata\";\nimport { ProjectMetadataOptions } from \"./project-metadata-options\";\nimport { AgentConfig } from \"../agent/agent-config\";\nimport { AgentConfigOptions } from \"../agent/agent-config-options\";\nimport { PnpmWorkspace, PnpmWorkspaceOptions } from \"../pnpm/pnpm-workspace\";\nimport { ResetTask, ResetTaskOptions } from \"../tasks/reset-task\";\nimport {\n ROOT_CI_TASK_NAME,\n TurboRepo,\n TurboRepoOptions,\n} from \"../turbo/turbo-repo\";\nimport { VERSION } from \"../versions\";\nimport { VSCodeConfig } from \"../vscode/vscode\";\nimport {\n addApproveMergeUpgradeWorkflow,\n type ApproveMergeUpgradeOptions,\n} from \"../workflows/approve-merge-upgrade\";\nimport { addBuildCompleteJob } from \"../workflows/build-complete-job\";\nimport {\n addSyncLabelsWorkflow,\n type SyncLabelsOptions,\n} from \"../workflows/sync-labels\";\n\nconst CONFIGULATOR_PACKAGE_NAME = \"@codedrifters/configulator\";\n\n/*******************************************************************************\n *\n * Monorepo Root Project.\n *\n * This project should be used as the base project for other projects in a\n * monorepo. The Monorepo root project generally won't contain any code, but it\n * will contain configuration for the monorepo, such as package management,\n * linting, testing, and other project-wide settings.\n *\n ******************************************************************************/\n\nexport interface IDependencyResolver {\n resolveDepsAndWritePackageJson(): boolean;\n}\n\n/**\n * Configuration options for the monorepo.\n */\nexport interface MonorepoProjectOptions extends Omit<\n TypeScriptProjectOptions,\n \"defaultReleaseBranch\"\n> {\n /**\n * Turn on Turborepo support.\n *\n * @default true\n */\n turbo?: boolean;\n\n /**\n * Optionsal options for turborepo config\n */\n turboOptions?: TurboRepoOptions;\n\n /**\n * Enable the reset task that deletes all build artifacts.\n *\n * @default true\n */\n resetTask?: boolean;\n\n /**\n * Options for the reset task.\n */\n resetTaskOptions?: ResetTaskOptions;\n\n /**\n * PNPM options for the monorepo.\n */\n pnpmOptions?: {\n /**\n * The version of PNPM to use in the monorepo.\n * @default VERSION.PNPM_VERSION\n * @see {@link src/versions.ts}\n */\n version?: string;\n\n /**\n * Optional pnpm options for the monorepo workspace file.\n */\n pnpmWorkspaceOptions?: PnpmWorkspaceOptions;\n };\n\n /**\n * When set, adds the approve-and-merge-upgrade workflow (ADR 0001 §2).\n * Uses a second GitHub App to approve and merge the dependency-upgrade PR\n * when it has the auto-approve label and head branch matches. Trigger types\n * exclude `opened` to prevent double approval.\n *\n * @see ApproveMergeUpgradeOptions\n */\n readonly approveMergeUpgradeOptions?: ApproveMergeUpgradeOptions;\n\n /**\n * Whether this monorepo consumes @codedrifters/configulator from a registry (npm).\n * When true, the upgrade workflow adds steps to sync configulator and synthesize.\n * Set to false when configulator is developed in this repo (e.g. workspace dependency).\n *\n * @default true\n */\n readonly configulatorRegistryConsumer?: boolean;\n\n /**\n * Project metadata configuration. Provides repository identity,\n * GitHub project context, and organizational details consumed by\n * AgentConfig and other features at synthesis time.\n *\n * - `undefined` or `{}`: auto-instantiate with auto-detection (default)\n * - `ProjectMetadataOptions`: explicit metadata configuration\n * - `false`: disable ProjectMetadata entirely\n *\n * @default {} (auto-detect from package.json)\n */\n readonly projectMetadata?: ProjectMetadataOptions | false;\n\n /**\n * AI agent configuration (Cursor, Claude Code rules).\n * Generates rule files at the monorepo root with auto-detected bundles\n * based on project and subproject introspection.\n *\n * - `true` or `{}`: enable with auto-detected defaults\n * - `AgentConfigOptions`: enable with explicit configuration\n * - `false` or `undefined`: disabled (default)\n *\n * @default false\n */\n readonly agentConfig?: AgentConfigOptions | boolean;\n\n /**\n * Sync GitHub labels from a config file using EndBug/label-sync.\n * Generates `.github/labels.yml` and a sync workflow.\n *\n * - `true` or `undefined`: enable with default priority labels (default)\n * - `SyncLabelsOptions`: enable with custom label configuration\n * - `false`: disable label syncing\n *\n * @default true\n */\n readonly syncLabels?: SyncLabelsOptions | boolean;\n}\n\ninterface AppliedOptions\n extends TypeScriptProjectOptions, MonorepoProjectOptions {}\n\n/**\n * Per-instance list of post-install dependency resolvers. Stored in a WeakMap\n * so MonorepoProject has no private instance property and its type remains\n * structural across package versions (avoids TS2322 when two configulator\n * versions are in the dependency tree).\n */\nconst postInstallDependenciesMap = new WeakMap<\n MonorepoProject,\n Array<() => boolean>\n>();\n\nexport class MonorepoProject extends TypeScriptAppProject {\n /**\n * Version of PNPM which the whole monorepo should use.\n */\n readonly pnpmVersion: string;\n\n /**\n * Whether this monorepo consumes configulator from a registry (drives upgrade workflow steps).\n */\n readonly configulatorRegistryConsumer: boolean;\n\n constructor(userOptions: MonorepoProjectOptions) {\n /***************************************************************************\n *\n * BUILD WORKFLOW OPTIONS\n *\n * discover some turbo options for build workflow, if needed.\n *\n **************************************************************************/\n\n const buildWorkflowOptions: Partial<BuildWorkflowOptions> = userOptions\n .turboOptions?.remoteCacheOptions\n ? TurboRepo.buildWorkflowOptions(\n userOptions.turboOptions.remoteCacheOptions,\n )\n : {};\n\n /***************************************************************************\n *\n * DEFAULT OPTIONS\n *\n * These are the default options unless you override with option inputs.\n *\n **************************************************************************/\n\n const defaultOptions: Omit<\n MonorepoProjectOptions,\n \"name\" | \"defaultReleaseBranch\"\n > = {\n /**\n * Use typescript based config file.\n */\n projenrcTs: true,\n\n /**\n * Projen version should be pinned to the local specified version.\n */\n projenVersion: \"catalog:\",\n\n /**\n * Use Prettier for code formatting.\n */\n prettier: true,\n\n /**\n * Not licensed by default.\n */\n licensed: false,\n\n /**\n * GitHub options for the monorepo.\n * Don't enable mergify by default.\n */\n githubOptions: {\n mergify: false,\n\n /**\n * Configure pull request linting to validate PR titles follow Conventional Commits.\n * By default, all conventional commit types are allowed, providing flexibility\n * for different types of changes (features, fixes, documentation, refactoring, etc.).\n */\n pullRequestLintOptions: {\n semanticTitleOptions: {\n /**\n * Allowed conventional commit types for PR titles.\n * This includes all standard types from the Conventional Commits specification:\n * - feat: New features\n * - fix: Bug fixes\n * - docs: Documentation changes\n * - style: Code style changes (formatting, etc.)\n * - refactor: Code refactoring\n * - perf: Performance improvements\n * - test: Test additions or changes\n * - build: Build system changes\n * - ci: CI configuration changes\n * - chore: Maintenance tasks\n * - revert: Revert commits\n */\n types: [\n \"feat\",\n \"fix\",\n \"docs\",\n \"style\",\n \"refactor\",\n \"perf\",\n \"test\",\n \"build\",\n \"ci\",\n \"chore\",\n \"revert\",\n ],\n },\n },\n },\n\n /**\n * Default PNPM version to use in the monorepo.\n */\n pnpmVersion: VERSION.PNPM_VERSION,\n\n /**\n * By default treat as a registry consumer (upgrade workflow syncs configulator).\n */\n configulatorRegistryConsumer: true,\n\n /**\n * We don't want sample code generated for the root project.\n */\n sampleCode: false,\n\n /**\n * Jest is not required in the root project.\n */\n jest: false,\n\n /**\n * Don't release the root project.\n */\n release: false,\n\n /**\n * Uppgrade dependencies automatically unless otherwise instructed.\n * Exclude @codedrifters/configulator so the default upgrade task does not\n * upgrade it (version is often managed in-repo or via a separate sync step).\n */\n depsUpgrade: true,\n depsUpgradeOptions: {\n exclude: [\"@codedrifters/configulator\"],\n workflowOptions: {\n schedule: UpgradeDependenciesSchedule.DAILY,\n },\n cooldown: 1,\n },\n\n /**\n * Disable tsconfig.dev.json in the root since we aren't going to be\n * developing any code here. It's just a task runner and configuration\n * tool for sub-projects.\n */\n disableTsconfigDev: true,\n\n /**\n * Kill the srcdir in the root since we aren't using one. Projen's\n * default `tsconfig.include` still points at `src/**\\/*.ts`, so\n * callers that want to treat the monorepo root as a pure shell\n * should see an empty include — consumers add their own entries via\n * `tsconfig.addInclude(...)` (e.g. `.projenrc.ts`, `projenrc/**\\/*.ts`).\n */\n tsconfig: {\n compilerOptions: {\n rootDir: undefined,\n },\n exclude: [\"node_modules\"],\n },\n\n /**\n * Enable turborepo by default.\n */\n turbo: true,\n\n /**\n * Enable reset task by default.\n */\n resetTask: true,\n\n /**\n * Include self as a devDep\n */\n devDeps: [\"@codedrifters/configulator\"],\n\n /**\n * PNPM options for the monorepo.\n */\n pnpmOptions: {\n pnpmWorkspaceOptions: {\n defaultCatalog: {\n [\"@types/node\"]: VERSION.TYPES_NODE_VERSION,\n [\"aws-cdk\"]: VERSION.AWS_CDK_CLI_VERSION,\n [\"aws-cdk-lib\"]: VERSION.AWS_CDK_LIB_VERSION,\n [\"projen\"]: VERSION.PROJEN_VERSION,\n [\"constructs\"]: VERSION.AWS_CONSTRUCTS_VERSION,\n [\"turbo\"]: VERSION.TURBO_VERSION,\n },\n },\n },\n };\n\n /***************************************************************************\n *\n * REQUIRED OPTIONS\n *\n * These options cannot be changed by the user.\n *\n **************************************************************************/\n\n const requiredOptions: Omit<TypeScriptProjectOptions, \"name\"> = {\n /**\n * This is required because it's standard practice and also to simplify\n * some workflow design.\n */\n defaultReleaseBranch: \"main\",\n\n /**\n * Use PNPM instead of the default (Yarn). Much of the ecosystem depends\n * on PNPM and making monorepos PNPM only simplifies many configurations.\n */\n packageManager: NodePackageManager.PNPM,\n\n /**\n * Some additional pre-build steps if we're using turbo's remote cache.\n * Set GIT_BRANCH_NAME so Turborepo remote cache hashes match between local and CI.\n */\n buildWorkflowOptions: {\n env: {\n GIT_BRANCH_NAME: \"${{ github.head_ref || github.ref_name }}\",\n ...buildWorkflowOptions?.env,\n ...userOptions.buildWorkflowOptions?.env,\n },\n permissions: {\n ...buildWorkflowOptions?.permissions,\n ...userOptions.buildWorkflowOptions?.permissions,\n },\n preBuildSteps: [\n ...(buildWorkflowOptions?.preBuildSteps ?? []),\n ...(userOptions.buildWorkflowOptions?.preBuildSteps ?? []),\n ],\n },\n };\n\n /***************************************************************************\n *\n * CONSTRUCTOR\n *\n * Combines default options with user provided options and required options.\n * Store the options in a const so we can use them after super(), farther\n * into the constructor for additional configuration.\n *\n **************************************************************************/\n\n const options: AppliedOptions = merge(\n defaultOptions,\n userOptions,\n requiredOptions,\n );\n\n super({ ...options });\n\n postInstallDependenciesMap.set(this, []);\n\n /**\n * Projen's TypeScriptProject seeds `tsconfig.include` with\n * `<srcdir>/**\\/*.ts` by default. MonorepoProject is a shell with no\n * srcdir, so drop that entry — consumers add their own includes (e.g.\n * `.projenrc.ts`, `projenrc/**\\/*.ts`) via `this.tsconfig?.addInclude`.\n */\n this.tsconfig?.removeInclude(`${this.srcdir}/**/*.ts`);\n\n /***************************************************************************\n *\n * PUBLIC PROPS\n *\n * Some props are hidden by Projen and we need to expose them for the\n * monorepo to work properly. This is where we store them.\n *\n **************************************************************************/\n\n this.pnpmVersion = options.pnpmVersion!;\n this.configulatorRegistryConsumer =\n options.configulatorRegistryConsumer ?? true;\n\n /***************************************************************************\n *\n * CUSTOM CONFIGS\n *\n * We add some additional configurations to the monorepo root project below\n * such as Turborepo, VS Code config, and the PNPM workspace file.\n *\n **************************************************************************/\n\n /**\n * Add VSCode configuration\n */\n new VSCodeConfig(this);\n\n /**\n * Add workspace definition to PNPM root\n */\n new PnpmWorkspace(this, options.pnpmOptions?.pnpmWorkspaceOptions);\n\n /**\n * Turn on turborepo support if requested.\n */\n if (options.turbo) {\n new TurboRepo(this, options.turboOptions);\n\n this.buildWorkflow?.addPostBuildSteps(\n {\n name: \"Build Sub Projects\",\n run: `npx projen ${ROOT_CI_TASK_NAME}`,\n },\n WorkflowSteps.uploadArtifact({\n name: \"Upload Turbo runs\",\n if: \"always()\",\n continueOnError: true,\n with: {\n name: \"turbo-runs\",\n path: \".turbo/runs\",\n },\n }),\n );\n }\n\n /**\n * Add reset task if enabled.\n */\n if (options.resetTask !== false) {\n const defaultResetTaskOptions: ResetTaskOptions = {\n pathsToRemove: [\"node_modules\", \".turbo\", \"dist\", \"lib\"],\n };\n const userResetTaskOptions = options.resetTaskOptions ?? {};\n const resetTaskOptions: ResetTaskOptions = merge(\n defaultResetTaskOptions,\n {\n ...userResetTaskOptions,\n pathsToRemove: [\n ...(defaultResetTaskOptions.pathsToRemove ?? []),\n ...(userResetTaskOptions.pathsToRemove ?? []),\n ],\n },\n );\n new ResetTask(this, resetTaskOptions);\n }\n\n /**\n * Specify package manager\n */\n // const pnpmVersion = options.pnpmVersion ?? VERSION.PNPM_VERSION;\n this.package.file.addOverride(\n \"packageManager\",\n `pnpm@${options.pnpmVersion}`,\n );\n\n /**\n * Add some silly things to the gitignore.\n */\n this.gitignore?.addPatterns(\".DS_Store\", \"test-reports\");\n\n /**\n * Use catalog versions for constructs and @types/node\n */\n this.addDevDeps(\"constructs@catalog:\", \"@types/node@catalog:\");\n\n if (options.approveMergeUpgradeOptions) {\n addApproveMergeUpgradeWorkflow(this, options.approveMergeUpgradeOptions);\n }\n\n /**\n * Project metadata — auto-instantiated unless explicitly disabled.\n */\n if (options.projectMetadata !== false) {\n new ProjectMetadata(\n this,\n typeof options.projectMetadata === \"object\"\n ? options.projectMetadata\n : {},\n );\n }\n\n /**\n * Enable AI agent configuration if requested.\n */\n if (options.agentConfig) {\n new AgentConfig(\n this,\n typeof options.agentConfig === \"object\" ? options.agentConfig : {},\n );\n }\n\n /**\n * Sync GitHub labels if enabled. When AgentConfig is present, its\n * active bundles contribute labels to `.github/labels.yml` so a\n * bundle can ship the labels its rules depend on.\n */\n if (options.syncLabels !== false) {\n const syncLabelsOptions =\n typeof options.syncLabels === \"object\" ? options.syncLabels : {};\n const agentConfig = AgentConfig.of(this);\n addSyncLabelsWorkflow(this, {\n ...syncLabelsOptions,\n bundles: syncLabelsOptions.bundles ?? agentConfig?.activeBundles,\n });\n }\n\n /**\n * Append the \"complete\" gate job to the build workflow (ADR 0004). Requires\n * build to succeed and all other jobs to succeed or be skipped.\n */\n if (this.buildWorkflow) {\n addBuildCompleteJob(this.buildWorkflow);\n }\n\n // Mutate the upgrade workflow job: add subproject upgrade step (always), and\n // for consumers add sync + synthesize before it. addPostBuildSteps runs too\n // late because the workflow is created in UpgradeDependencies constructor.\n const upgradeWorkflow = this.github?.tryFindWorkflow(\"upgrade\");\n const upgradeJob = upgradeWorkflow?.getJob(\"upgrade\");\n const jobWithSteps =\n upgradeJob && \"steps\" in upgradeJob ? upgradeJob : undefined;\n if (jobWithSteps?.steps && Array.isArray(jobWithSteps.steps)) {\n const insertIndex = 4; // after checkout, setup, install, upgrade\n if (this.configulatorRegistryConsumer) {\n jobWithSteps.steps.splice(insertIndex, 0, {\n name: `Sync ${CONFIGULATOR_PACKAGE_NAME} in workspace`,\n run: `pnpm update -r ${CONFIGULATOR_PACKAGE_NAME}`,\n });\n jobWithSteps.steps.splice(insertIndex + 1, 0, {\n name: \"Synthesize\",\n run: this.runTaskCommand(this.defaultTask!),\n });\n }\n jobWithSteps.steps.splice(\n insertIndex + (this.configulatorRegistryConsumer ? 2 : 0),\n 0,\n {\n name: \"Run subproject upgrades\",\n run: \"pnpm -r run upgrade\",\n },\n );\n }\n }\n\n /**\n * Allows a sub project to request installation of dependency at the Monorepo root\n * They must provide a function that is executed after dependencies have been installed\n * If this function returns true, the install command is run for a second time after all sub project requests have run.\n * This is used to resolve dependency versions from `*` to a concrete version constraint.\n */\n public requestInstallDependencies(resolver: IDependencyResolver) {\n postInstallDependenciesMap\n .get(this)!\n .push(resolver.resolveDepsAndWritePackageJson);\n }\n\n /**\n * Hooks into the install dependencies cycle\n */\n public postSynthesize() {\n const postInstallDependencies = postInstallDependenciesMap.get(this);\n if (postInstallDependencies?.length) {\n const nodePkg: any = this.package;\n nodePkg.installDependencies();\n\n const completedRequests = postInstallDependencies.map((request) =>\n request(),\n );\n if (completedRequests.some(Boolean)) {\n nodePkg.installDependencies();\n }\n\n postInstallDependenciesMap.set(this, []);\n }\n }\n}\n","import { Component, Project } from \"projen\";\nimport { TypeScriptProject } from \"../projects/typescript-project\";\nimport { TurboRepo } from \"../turbo/turbo-repo\";\nimport { TurboRepoTask } from \"../turbo/turbo-repo-task\";\n\n/*******************************************************************************\n *\n * Reset Task Component\n *\n * Adds a \"reset\" task that deletes all build artifacts produced by the build\n * process. This includes node_modules, lib, dist, coverage, test-reports,\n * .turbo, and tsconfig.tsbuildinfo.\n *\n ******************************************************************************/\n\nexport interface ResetTaskOptions {\n /**\n * Custom output directory to delete (overrides tsconfig artifactsDirectory detection).\n *\n * @default - detected from typescript project.artifactsDirectory or \"lib\"\n */\n readonly artifactsDirectory?: string;\n\n /**\n * Array of glob patterns for paths to remove.\n * If empty, the artifactsDirectory will be added automatically.\n *\n * @default []\n */\n readonly pathsToRemove?: string[];\n\n /**\n * Name of the task to create.\n *\n * @default \"reset\"\n */\n readonly taskName?: string;\n}\n\nexport class ResetTask extends Component {\n /**\n * Static method to discover reset task in a project.\n */\n public static of(project: Project): ResetTask | undefined {\n const isDefined = (c: Component): c is ResetTask => c instanceof ResetTask;\n return project.components.find(isDefined);\n }\n\n /**\n * The output directory to delete (from tsconfig or custom).\n */\n public readonly artifactsDirectory: string;\n\n /**\n * The final array of paths that will be removed by the reset task.\n */\n public readonly pathsToRemove: string[];\n\n /**\n * The name of the task that was created.\n */\n public readonly taskName: string;\n\n constructor(\n public readonly project: Project,\n options: ResetTaskOptions = {},\n ) {\n super(project);\n\n /**\n * Determine the output directory.\n * 1. Use custom artifactsDirectory if provided\n * 2. Use the artifacts directory if project is TypeScriptProject\n * 3. Default to \"lib\"\n */\n this.artifactsDirectory = options.artifactsDirectory\n ? options.artifactsDirectory\n : project instanceof TypeScriptProject\n ? project.artifactsDirectory\n : \"lib\";\n\n /**\n * Build the paths array to remove.\n * If pathsToRemove is empty, add artifactsDirectory.\n * If pathsToRemove is not empty, use it as-is (artifactsDirectory is not automatically added).\n * Remove duplicate entries from the array.\n */\n const pathsToRemove = options.pathsToRemove ?? [];\n const finalPaths =\n pathsToRemove.length === 0 ? [this.artifactsDirectory] : pathsToRemove;\n\n /**\n * Remove duplicate paths from the array.\n */\n this.pathsToRemove = Array.from(new Set(finalPaths));\n\n /**\n * Determine the task name.\n */\n this.taskName = options.taskName ?? \"reset\";\n\n /**\n * Create the reset task.\n */\n const resetTask = this.project.tasks.addTask(this.taskName, {\n description:\n \"Delete build artifacts specified by pathsToRemove option, or artifactsDirectory if pathsToRemove is empty\",\n });\n\n /**\n * Delete build artifacts with existence checks.\n * Using shell conditionals to only delete if paths exist.\n * Using -e to check existence (works for both files and directories).\n */\n this.pathsToRemove.forEach((path) => {\n resetTask.exec(`[ -e \"${path}\" ] && rm -rf ${path} || true`);\n });\n\n /**\n * Turbo tasks are added after all components are created.\n * This assumes turbo is built first so that it's available to be\n * referenced. This could introduce problems in future but works for now.\n */\n\n /**\n * Check if turborepo is active.\n */\n const rootHasTurbo = TurboRepo.of(this.project.root) !== undefined;\n const isSubproject = this.project !== this.project.root;\n const isRootProject = this.project === this.project.root;\n\n /**\n * If turborepo is active for the subproject, add turbo tasks.\n */\n if (isSubproject && rootHasTurbo) {\n /**\n * Get TurboRepo instance for this subproject.\n * It should exist by now since preSynthesize runs after all components are created.\n */\n const turbo = TurboRepo.of(this.project);\n if (turbo && !turbo.isRootProject) {\n /**\n * Create turbo:reset task (or turbo:${taskName}).\n */\n const turboResetTask = new TurboRepoTask(this.project, {\n name: `turbo:${this.taskName}`,\n cache: false,\n });\n turbo.tasks.push(turboResetTask);\n\n /**\n * Create a turbo task with the same name as the reset task.\n */\n const turboTaskWithSameName = new TurboRepoTask(this.project, {\n name: this.taskName,\n cache: false,\n });\n turbo.tasks.push(turboTaskWithSameName);\n\n /**\n * turboResetTask depends on turboTaskWithSameName so that the reset task\n * can be run across all suprojects using turbo:reset as the entry point.\n */\n turboResetTask.dependsOn.push(turboTaskWithSameName.name);\n }\n }\n\n /**\n * If reset-task is in the root project, add a turbo task that will trigger\n * all the subtasks using dependsOn of \"^turbo:reset\".\n */\n if (isRootProject && rootHasTurbo) {\n const turbo = TurboRepo.of(this.project);\n if (turbo && turbo.isRootProject) {\n /**\n * Create turbo:reset task (or turbo:${taskName}) in the root project.\n * The ^ prefix means \"run this task in all dependencies first\".\n */\n const rootTurboResetTask = new TurboRepoTask(this.project, {\n name: `turbo:${this.taskName}`,\n dependsOn: [`^turbo:${this.taskName}`],\n cache: false,\n });\n turbo.tasks.push(rootTurboResetTask);\n\n /**\n * Create a turbo task with the same name as the reset task.\n */\n const turboTaskWithSameName = new TurboRepoTask(this.project, {\n name: this.taskName,\n cache: false,\n });\n turbo.tasks.push(turboTaskWithSameName);\n\n /**\n * rootTurboResetTask depends on turboTaskWithSameName so that the reset task\n * can be run across all suprojects using turbo:reset as the entry point.\n */\n rootTurboResetTask.dependsOn.push(turboTaskWithSameName.name);\n\n /**\n * Create reset:all task - a projen task that calls the turbo task.\n * This is similar to build:all in turbo-repo.ts.\n */\n const resetAllTask = this.project.tasks.addTask(\n `${this.taskName}:all`,\n {\n description: `Reset all build artifacts across the monorepo by running turbo:${this.taskName} in all subprojects.`,\n },\n );\n resetAllTask.exec(\"turbo telemetry disable\");\n resetAllTask.exec(\n `turbo turbo:${this.taskName} --summarize --concurrency=10`,\n );\n resetAllTask.exec(`pnpm ${this.taskName}`);\n }\n }\n }\n}\n","import { Component, vscode } from \"projen\";\nimport { TypeScriptAppProject } from \"projen/lib/typescript\";\n\n/*******************************************************************************\n *\n * Configure VSCode Settings\n *\n ******************************************************************************/\n\nexport class VSCodeConfig extends Component {\n constructor(project: TypeScriptAppProject) {\n super(project);\n\n /**\n * Create instance of config file.\n */\n const vsConfig = new vscode.VsCode(project);\n\n /**\n * Add some basic configuration settings to the VS Code settings file:\n *\n * - Set the tab size to 2 spaces\n * - Enable bracket pair colorization\n * - Highlight active bracket pairs\n * - Add rulers at 80 and 120 characters\n */\n const vsSettings = new vscode.VsCodeSettings(vsConfig);\n vsSettings.addSetting(\"editor.tabSize\", 2);\n vsSettings.addSetting(\"editor.detectIndentation\", false);\n vsSettings.addSetting(\"editor.bracketPairColorization.enabled\", true);\n vsSettings.addSetting(\"editor.guides.bracketPairs\", \"active\");\n vsSettings.addSetting(\"editor.rulers\", [80, 120]);\n\n /**\n * Add some ESLint specific settings to the VS Code settings file.\n */\n vsSettings.addSetting(\n \"editor.codeActionsOnSave\",\n { \"source.fixAll.eslint\": \"explicit\" },\n \"typescript\",\n );\n }\n}\n","import { JobPermission } from \"projen/lib/github/workflows-model\";\nimport type { NodeProject } from \"projen/lib/javascript\";\n\n/** Merge methods supported by enable-pull-request-automerge. */\nexport const MERGE_METHODS = {\n SQUASH: \"squash\",\n MERGE: \"merge\",\n REBASE: \"rebase\",\n} as const;\n\n/** Merge method for the approve-and-merge-upgrade workflow. */\nexport type MergeMethod = (typeof MERGE_METHODS)[keyof typeof MERGE_METHODS];\n\n/**\n * Options for the approve-and-merge-upgrade workflow (ADR 0001 §2).\n * When set, adds a workflow that approves and merges the dependency-upgrade PR\n * when it has the auto-approve label and head branch matches. Trigger types\n * exclude `opened` to prevent double approval when the PR is created with the label.\n */\nexport interface ApproveMergeUpgradeOptions {\n /**\n * Workflow file name (display name in Actions tab).\n * @default \"approve-and-merge-upgrade\"\n */\n readonly workflowName?: string;\n\n /**\n * Label that must be present on the PR to trigger approve-and-merge.\n * @default \"auto-approve\"\n */\n readonly autoApproveLabel?: string;\n\n /**\n * Head branch name the PR must target (e.g. the branch created by the upgrade workflow).\n * @default \"github-actions/upgrade\"\n */\n readonly headBranch?: string;\n\n /**\n * GitHub usernames allowed as PR authors (e.g. automation bot logins).\n * The workflow runs only when the PR user is in this list.\n */\n readonly allowedUsernames: string[];\n\n /**\n * Repository secret name for the approval GitHub App ID.\n * @default \"APPROVAL_APP_ID\"\n */\n readonly approvalAppIdSecret?: string;\n\n /**\n * Repository secret name for the approval GitHub App private key (PEM).\n * @default \"APPROVAL_APP_PRIVATE_KEY\"\n */\n readonly approvalAppPrivateKeySecret?: string;\n\n /**\n * Merge method for enable-pull-request-automerge.\n * @default \"squash\"\n */\n readonly mergeMethod?: MergeMethod;\n\n /**\n * Optional branch filters for pull_request_target (e.g. base branches).\n * @see https://docs.github.com/en/actions/using-workflows/events-that-trigger-workflows#pull_request_target\n */\n readonly branches?: string[];\n}\n\nconst DEFAULT_WORKFLOW_NAME = \"approve-and-merge-upgrade\";\nconst DEFAULT_AUTO_APPROVE_LABEL = \"auto-approve\";\nconst DEFAULT_HEAD_BRANCH = \"github-actions/upgrade\";\nconst DEFAULT_APPROVAL_APP_ID_SECRET = \"APPROVAL_APP_ID\";\nconst DEFAULT_APPROVAL_APP_PRIVATE_KEY_SECRET = \"APPROVAL_APP_PRIVATE_KEY\";\nconst DEFAULT_MERGE_METHOD = MERGE_METHODS.SQUASH;\n\n/**\n * Trigger types for pull_request_target. Excludes `opened` so that when the\n * upgrade workflow creates a PR with the auto-approve label, GitHub emits both\n * `opened` and `labeled` and we avoid running the workflow twice (double approval).\n */\nconst PULL_REQUEST_TARGET_TYPES = [\n \"labeled\",\n \"synchronize\",\n \"reopened\",\n \"ready_for_review\",\n] as const;\n\n/**\n * Adds the approve-and-merge-upgrade workflow to the project.\n * Uses a GitHub App token for approve + enable automerge (squash by default).\n *\n * @param project - A NodeProject with GitHub (e.g. MonorepoProject)\n * @param options - Options for the workflow; allowedUsernames is required\n */\nexport function addApproveMergeUpgradeWorkflow(\n project: NodeProject,\n options: ApproveMergeUpgradeOptions,\n): void {\n const workflowName = options.workflowName ?? DEFAULT_WORKFLOW_NAME;\n const autoApproveLabel =\n options.autoApproveLabel ?? DEFAULT_AUTO_APPROVE_LABEL;\n const headBranch = options.headBranch ?? DEFAULT_HEAD_BRANCH;\n const allowedUsernames = options.allowedUsernames;\n const appIdSecret =\n options.approvalAppIdSecret ?? DEFAULT_APPROVAL_APP_ID_SECRET;\n const privateKeySecret =\n options.approvalAppPrivateKeySecret ??\n DEFAULT_APPROVAL_APP_PRIVATE_KEY_SECRET;\n const mergeMethod = options.mergeMethod ?? DEFAULT_MERGE_METHOD;\n\n const workflow = project.github?.addWorkflow(workflowName);\n if (!workflow) return;\n\n workflow.on({\n pullRequestTarget: {\n types: [...PULL_REQUEST_TARGET_TYPES],\n ...(options.branches && options.branches.length > 0\n ? { branches: options.branches }\n : {}),\n },\n });\n\n const jobCondition = [\n `contains(github.event.pull_request.labels.*.name, '${autoApproveLabel}')`,\n `github.event.pull_request.head.ref == '${headBranch}'`,\n `(${allowedUsernames.map((u) => `github.event.pull_request.user.login == '${u}'`).join(\" || \")})`,\n ].join(\" && \");\n\n workflow.addJobs({\n \"approve-and-merge\": {\n name: \"Approve and merge upgrade PR\",\n runsOn: [\"ubuntu-latest\"],\n permissions: {\n pullRequests: JobPermission.WRITE,\n contents: JobPermission.WRITE,\n },\n if: jobCondition,\n steps: [\n {\n name: \"Generate token\",\n id: \"generate_token\",\n uses: \"actions/create-github-app-token@v2\",\n with: {\n \"app-id\": `\\${{ secrets.${appIdSecret} }}`,\n \"private-key\": `\\${{ secrets.${privateKeySecret} }}`,\n },\n },\n {\n name: \"Auto-approve\",\n uses: \"hmarr/auto-approve-action@f0939ea97e9205ef24d872e76833fa908a770363\",\n with: {\n \"github-token\": \"${{ steps.generate_token.outputs.token }}\",\n },\n },\n {\n name: \"Enable auto-merge (squash)\",\n uses: \"peter-evans/enable-pull-request-automerge@v3\",\n with: {\n token: \"${{ steps.generate_token.outputs.token }}\",\n \"pull-request-number\": \"${{ github.event.pull_request.number }}\",\n \"merge-method\": mergeMethod,\n },\n },\n ],\n },\n });\n}\n","import { BuildWorkflow } from \"projen/lib/build\";\nimport { JobPermission } from \"projen/lib/github/workflows-model\";\n\n/** Job ID of the main build job (Projen constant). */\nconst BUILD_JOB_ID = \"build\";\n\n/** Name of the gate job appended to build workflows (ADR 0004). */\nexport const COMPLETE_JOB_ID = \"complete\";\n\n/**\n * Projen's BuildWorkflow holds the underlying GithubWorkflow in a private\n * property. We use this shape to access it (cast via unknown).\n */\ninterface BuildWorkflowWithWorkflow {\n workflow: {\n jobs: Record<string, unknown>;\n addJob(id: string, job: Record<string, unknown>): void;\n };\n}\n\n/**\n * Builds the run script for the complete job step. Requires the build job to\n * succeed; all other jobs must succeed or be skipped (ADR 0004).\n * Uses \\$ so the output contains literal ${{ }} for GitHub Actions expressions.\n */\nfunction buildCompleteJobRunScript(jobIds: string[]): string {\n const lines: string[] = [];\n for (const id of jobIds) {\n const expr = \"${{ needs.\" + id + \".result }}\";\n if (id === BUILD_JOB_ID) {\n lines.push(\n `if [ \"${expr}\" != \"success\" ]; then echo \"Job ${id} must succeed\"; exit 1; fi`,\n );\n } else {\n lines.push(\n `if [ \"${expr}\" != \"success\" ] && [ \"${expr}\" != \"skipped\" ]; then echo \"Job ${id} must succeed or be skipped\"; exit 1; fi`,\n );\n }\n }\n return lines.join(\"\\n\");\n}\n\n/**\n * Appends the \"complete\" gate job to a build workflow (ADR 0004, issue #165).\n * The job runs after all other jobs, uses {@code if: always()}, and succeeds\n * only when the build job succeeded and every other job succeeded or was skipped.\n * Call this for the default build workflow and for any build workflow created\n * by Configulator (e.g. AwsDeployWorkflow).\n *\n * @param buildWorkflow The Projen BuildWorkflow to append the complete job to.\n */\nexport function addBuildCompleteJob(buildWorkflow: BuildWorkflow): void {\n const w = (buildWorkflow as unknown as BuildWorkflowWithWorkflow).workflow;\n if (!w?.jobs || typeof w.addJob !== \"function\") {\n return;\n }\n const jobIds = Object.keys(w.jobs).filter((id) => id !== COMPLETE_JOB_ID);\n if (jobIds.length === 0) {\n return;\n }\n const runScript = buildCompleteJobRunScript(jobIds);\n w.addJob(COMPLETE_JOB_ID, {\n name: \"Complete\",\n needs: jobIds,\n if: \"always()\",\n runsOn: [\"ubuntu-latest\"],\n permissions: {\n contents: JobPermission.NONE,\n },\n steps: [\n {\n name: \"Verify all jobs succeeded or were skipped\",\n run: runScript,\n },\n ],\n });\n}\n","import { Component, Project, YamlFile } from \"projen\";\nimport { JobPermission } from \"projen/lib/github/workflows-model\";\nimport type { NodeProject } from \"projen/lib/javascript\";\nimport type { AgentRuleBundle } from \"../agent/agent-config-options\";\n\n/** A single GitHub label definition for EndBug/label-sync. */\nexport interface LabelDefinition {\n /** Label name (e.g. \"priority:high\"). */\n readonly name: string;\n\n /** Hex color without the leading `#` (e.g. \"B60205\"). */\n readonly color: string;\n\n /** Short description shown in the GitHub UI. */\n readonly description: string;\n}\n\n/** Options for the sync-labels workflow and labels config file. */\nexport interface SyncLabelsOptions {\n /**\n * Additional labels to sync alongside the standard defaults.\n * Merged with DEFAULT_STATUS_LABELS, DEFAULT_PRIORITY_LABELS, and\n * DEFAULT_TYPE_LABELS (standard labels are always included).\n */\n readonly labels?: ReadonlyArray<LabelDefinition>;\n\n /**\n * Remove labels from the repo that are not in the config file.\n * @default true\n */\n readonly deleteOtherLabels?: boolean;\n\n /**\n * Workflow file name (display name in the Actions tab).\n * @default \"sync-labels\"\n */\n readonly workflowName?: string;\n\n /**\n * Agent bundles whose contributed labels should be merged into\n * `.github/labels.yml`. Typically populated by the project type from\n * `AgentConfig.of(project)?.activeBundles` so bundle-supplied labels\n * only appear when the bundle is actually enabled.\n *\n * Merge order: Tier 1 defaults → bundle labels → user-supplied `labels`\n * (later entries override earlier ones on name collision).\n */\n readonly bundles?: ReadonlyArray<AgentRuleBundle>;\n}\n\n/** Default status labels. */\nexport const DEFAULT_STATUS_LABELS: ReadonlyArray<LabelDefinition> = [\n {\n name: \"status:ready\",\n color: \"0E8A16\",\n description: \"Task is ready for pickup\",\n },\n {\n name: \"status:in-progress\",\n color: \"FBCA04\",\n description: \"Actively being worked on\",\n },\n {\n name: \"status:ready-for-review\",\n color: \"1D76DB\",\n description: \"PR opened and awaiting review\",\n },\n {\n name: \"status:blocked\",\n color: \"D93F0B\",\n description: \"Blocked on a dependency or question\",\n },\n {\n name: \"status:done\",\n color: \"6F42C1\",\n description: \"Task completed and closed\",\n },\n {\n name: \"status:deferred\",\n color: \"C2E0C6\",\n description: \"Intentionally parked — not ready for pickup\",\n },\n {\n name: \"status:needs-attention\",\n color: \"FF0000\",\n description: \"Requires human review\",\n },\n];\n\n/** Default priority labels. */\nexport const DEFAULT_PRIORITY_LABELS: ReadonlyArray<LabelDefinition> = [\n {\n name: \"priority:critical\",\n color: \"B60205\",\n description: \"Critical priority — address immediately\",\n },\n {\n name: \"priority:high\",\n color: \"D93F0B\",\n description: \"High priority — pick before normal\",\n },\n {\n name: \"priority:medium\",\n color: \"E4E669\",\n description: \"Medium priority\",\n },\n {\n name: \"priority:low\",\n color: \"D4C5F9\",\n description: \"Low priority — skip if higher-priority work exists\",\n },\n {\n name: \"priority:trivial\",\n color: \"EDEDED\",\n description: \"Trivial priority — address when convenient\",\n },\n];\n\n/** Default type labels — one per conventional commit type. */\nexport const DEFAULT_TYPE_LABELS: ReadonlyArray<LabelDefinition> = [\n {\n name: \"type:feat\",\n color: \"1D76DB\",\n description: \"New feature or functionality\",\n },\n {\n name: \"type:fix\",\n color: \"D73A4A\",\n description: \"Bug fix\",\n },\n {\n name: \"type:docs\",\n color: \"0075CA\",\n description: \"Documentation only\",\n },\n {\n name: \"type:style\",\n color: \"BFD4F2\",\n description: \"Code style (formatting, whitespace) — no logic change\",\n },\n {\n name: \"type:refactor\",\n color: \"A2EEEF\",\n description: \"Code restructure — no feature or fix\",\n },\n {\n name: \"type:perf\",\n color: \"F9D0C4\",\n description: \"Performance improvement\",\n },\n {\n name: \"type:test\",\n color: \"BFD4F2\",\n description: \"Adding or updating tests\",\n },\n {\n name: \"type:build\",\n color: \"E6CCF5\",\n description: \"Build system or external dependencies\",\n },\n {\n name: \"type:ci\",\n color: \"D4C5F9\",\n description: \"CI configuration changes\",\n },\n {\n name: \"type:chore\",\n color: \"E6E6E6\",\n description: \"Maintenance tasks (deps, tooling, config)\",\n },\n {\n name: \"type:revert\",\n color: \"EDEDED\",\n description: \"Revert a previous commit\",\n },\n {\n name: \"type:release\",\n color: \"0E8A16\",\n description: \"Release preparation and version bumps\",\n },\n {\n name: \"type:hotfix\",\n color: \"B60205\",\n description: \"Urgent production fix\",\n },\n];\n\nconst DEFAULT_WORKFLOW_NAME = \"sync-labels\";\nconst LABELS_CONFIG_PATH = \".github/labels.yml\";\n\n/**\n * Adds a labels config file and a GitHub Actions workflow that syncs\n * labels to the repository using EndBug/label-sync.\n */\nexport function addSyncLabelsWorkflow(\n project: NodeProject,\n options: SyncLabelsOptions,\n): void {\n const workflowName = options.workflowName ?? DEFAULT_WORKFLOW_NAME;\n const deleteOtherLabels = options.deleteOtherLabels ?? true;\n\n // Merge order: Tier 1 defaults → bundle labels → user-supplied. Later\n // entries override earlier ones on name collision, so a consumer can\n // always override a bundle-contributed label without disabling the bundle.\n const labelMap = new Map<string, LabelDefinition>();\n for (const label of DEFAULT_STATUS_LABELS) {\n labelMap.set(label.name, label);\n }\n for (const label of DEFAULT_PRIORITY_LABELS) {\n labelMap.set(label.name, label);\n }\n for (const label of DEFAULT_TYPE_LABELS) {\n labelMap.set(label.name, label);\n }\n for (const bundle of options.bundles ?? []) {\n for (const label of bundle.labels ?? []) {\n labelMap.set(label.name, label);\n }\n }\n for (const label of options.labels ?? []) {\n labelMap.set(label.name, label);\n }\n const allLabels = [...labelMap.values()];\n\n // Generate .github/labels.yml\n new LabelsFile(project, allLabels);\n\n // Generate the sync workflow\n const workflow = project.github?.addWorkflow(workflowName);\n if (!workflow) {\n return;\n }\n\n workflow.on({\n push: {\n branches: [\"main\"],\n paths: [LABELS_CONFIG_PATH],\n },\n workflowDispatch: {},\n });\n\n workflow.addJobs({\n sync: {\n name: \"Sync labels\",\n runsOn: [\"ubuntu-latest\"],\n permissions: {\n contents: JobPermission.READ,\n issues: JobPermission.WRITE,\n },\n steps: [\n {\n name: \"Checkout\",\n uses: \"actions/checkout@v6\",\n },\n {\n name: \"Sync labels\",\n uses: \"EndBug/label-sync@v2\",\n with: {\n \"config-file\": LABELS_CONFIG_PATH,\n \"delete-other-labels\": deleteOtherLabels,\n token: \"${{ secrets.GITHUB_TOKEN }}\",\n },\n },\n ],\n },\n });\n}\n\n/**\n * Projen component that writes .github/labels.yml.\n * Separated so the YAML file participates in the normal synth lifecycle.\n */\nclass LabelsFile extends Component {\n constructor(project: Project, labels: ReadonlyArray<LabelDefinition>) {\n super(project);\n\n new YamlFile(project, LABELS_CONFIG_PATH, {\n obj: labels.map((l) => ({\n name: l.name,\n color: l.color,\n description: l.description,\n })),\n committed: true,\n });\n }\n}\n","import { awscdk } from \"projen\";\nimport { BuildWorkflow } from \"projen/lib/build\";\nimport {\n NodePackageManager,\n Transform,\n UpgradeDependenciesSchedule,\n} from \"projen/lib/javascript\";\nimport { ReleaseTrigger } from \"projen/lib/release\";\nimport { merge } from \"ts-deepmerge\";\nimport { MonorepoProject } from \"./monorepo-project\";\nimport { TestRunner } from \"./typescript-project\";\nimport { AgentConfig } from \"../agent/agent-config\";\nimport { AgentConfigOptions } from \"../agent/agent-config-options\";\nimport {\n AwsDeploymentConfig,\n AwsDeploymentTarget,\n AwsDeploymentTargetOptions,\n} from \"../aws\";\nimport { PnpmWorkspace } from \"../pnpm\";\nimport { ResetTask, ResetTaskOptions } from \"../tasks/reset-task\";\nimport { TurboRepo } from \"../turbo\";\nimport { VERSION } from \"../versions\";\nimport { Vitest, VitestOptions } from \"../vitest\";\nimport {\n AwsDeployWorkflow,\n DeployWorkflowOptions,\n} from \"../workflows/aws-deploy-workflow\";\nimport {\n AwsTeardownWorkflow,\n AwsTeardownWorkflowOptions,\n} from \"../workflows/aws-teardown-workflow\";\n\n/**\n * Configuration options for AwsCdkProject.\n *\n * AwsCdkProject must be parented to a `MonorepoProject` — the constructor\n * throws otherwise. Configulator assumes a single-package repo is still a\n * monorepo (with one workspace) so all conventions hold uniformly.\n */\nexport interface AwsCdkProjectOptions extends Omit<\n awscdk.AwsCdkTypeScriptAppOptions,\n \"defaultReleaseBranch\"\n> {\n /**\n * AWS deployment targets (dev / stage / prod accounts and regions). Each\n * entry creates an `AwsDeploymentTarget` component on the project.\n */\n readonly deploymentTargets?: Array<AwsDeploymentTargetOptions>;\n\n /**\n * AWS deploy workflows. If omitted, one workflow is auto-generated per\n * unique `awsStageType` present in `deploymentTargets`. Each auto-generated\n * workflow renders to its own `.github/workflows/*.yml` file.\n *\n * Pass an empty array (`[]`) to opt out of auto-derivation entirely without\n * supplying any workflows of your own — the array is truthy and short-circuits\n * the default. Useful when you intend to attach deploy jobs to an existing\n * build workflow yourself.\n */\n readonly deployWorkflows?: Array<DeployWorkflowOptions>;\n\n /**\n * Optional shared `BuildWorkflow` to attach all auto-derived deploy jobs to.\n * When set, every workflow generated from `deploymentTargets` re-uses this\n * build workflow instead of creating its own. Default behavior (omit) is one\n * separate yml file per stage type.\n *\n * Distinct from `buildWorkflow: boolean` inherited from\n * `AwsCdkTypeScriptAppOptions`, which toggles whether the projen-managed\n * build workflow is generated at all.\n */\n readonly sharedBuildWorkflow?: BuildWorkflow;\n\n /**\n * Test runner to use.\n *\n * @default TestRunner.JEST\n */\n readonly testRunner?: TestRunner;\n\n /**\n * Options for Vitest (only used when testRunner is 'vitest').\n */\n readonly vitestOptions?: VitestOptions;\n\n /**\n * Enable the reset task that deletes all build artifacts.\n *\n * @default true\n */\n readonly resetTask?: boolean;\n\n /**\n * Options for the reset task.\n */\n readonly resetTaskOptions?: ResetTaskOptions;\n\n /**\n * AI agent configuration (Cursor, Claude Code rules). Opt-in per project;\n * not inherited from the parent `MonorepoProject`.\n *\n * @default false\n */\n readonly agentConfig?: AgentConfigOptions | boolean;\n\n /**\n * Scheduled teardown workflow options. When provided, an `AwsTeardownWorkflow`\n * is attached to the parent `MonorepoProject` that periodically deletes\n * orphaned CloudFormation stacks whose branch no longer exists.\n */\n readonly teardownWorkflow?: AwsTeardownWorkflowOptions;\n}\n\n/**\n * AWS CDK TypeScript application with CodeDrifters conventions baked in.\n *\n * Always creates an `AwsDeploymentConfig` component (even with zero deployment\n * targets) so the `synth` task is consistently rewritten to emit into\n * `dist/<project-path>/cdk.out`. This is intentional and not opt-out: it\n * funnels every package's CDK output into one root-level `dist/` tree so\n * GitHub Actions workflows can pass artifacts between jobs uniformly.\n */\nexport class AwsCdkProject extends awscdk.AwsCdkTypeScriptApp {\n constructor(userOptions: AwsCdkProjectOptions) {\n /**\n * Configulator requires every project to live inside a MonorepoProject.\n * The catalog-based @types/node pin, the workspace install hook, and the\n * deploy workflow all assume the parent exists.\n */\n if (!(userOptions.parent instanceof MonorepoProject)) {\n throw new Error(\n \"AwsCdkProject must be parented to a MonorepoProject. Pass `parent: <MonorepoProject>` in the project options.\",\n );\n }\n\n const parent = userOptions.parent;\n const pnpmVersion = parent.pnpmVersion;\n const pnpmWorkspace = PnpmWorkspace.of(parent);\n\n /*************************************************************************\n *\n * Default Options\n *\n ************************************************************************/\n\n const testRunner = userOptions.testRunner ?? TestRunner.JEST;\n const useJest = testRunner === TestRunner.JEST;\n\n const defaultOptions: Omit<AwsCdkProjectOptions, \"name\"> & {\n defaultReleaseBranch: string;\n cdkVersion: string;\n } = {\n defaultReleaseBranch: \"main\",\n\n /**\n * Enable reset task by default.\n */\n resetTask: true,\n\n /**\n * Packaging options.\n */\n packageManager: NodePackageManager.PNPM,\n pnpmVersion: pnpmVersion,\n licensed: userOptions.license !== undefined || false,\n copyrightOwner: \"CodeDrifters\",\n release: false,\n\n /**\n * Don't add sample code.\n */\n sampleCode: false,\n\n /**\n * CDK versions sourced from the configulator-managed catalog.\n */\n cdkVersion: VERSION.AWS_CDK_LIB_VERSION,\n cdkCliVersion: VERSION.AWS_CDK_CLI_VERSION,\n\n ...(useJest\n ? {\n /**\n * Make sure jest config is stored outside of package.json and use\n * SWC for faster compilation (matches TypeScriptProject).\n */\n jestOptions: {\n configFilePath: \"jest.config.json\",\n jestConfig: {\n roots: [`<rootDir>/src`],\n transform: {\n [\"^.+\\\\.[t]sx?$\"]: new Transform(\"@swc/jest\"),\n },\n moduleFileExtensions: [\"js\", \"ts\"],\n },\n },\n devDeps: [\"@swc/jest\", \"@swc/core\"] as Array<string>,\n }\n : {\n jest: false,\n devDeps: [] as Array<string>,\n }),\n\n /**\n * Turn on prettier formatting.\n */\n prettier: true,\n\n /**\n * Don't package test files.\n */\n npmIgnoreOptions: {\n ignorePatterns: [\"*.spec.*\", \"*.test.*\"],\n },\n\n /**\n * Options for the automated dependency upgrade task / workflow.\n * Exclude any packages managed by the parent project's default catalog\n * so the catalog stays the source of truth.\n */\n depsUpgrade: true,\n depsUpgradeOptions: {\n workflow: false,\n exclude: Object.keys(pnpmWorkspace?.defaultCatalog || {}),\n workflowOptions: {\n schedule: UpgradeDependenciesSchedule.WEEKLY,\n },\n cooldown: 1,\n },\n\n /**\n * Only release when the package source content or package.json changes.\n */\n releaseTrigger: ReleaseTrigger.continuous({\n paths: [\n `${userOptions.outdir}/src/**`,\n `${userOptions.outdir}/package.json`,\n ],\n }),\n };\n\n /*************************************************************************\n *\n * Merge defaults into user options\n *\n ************************************************************************/\n\n const options: AwsCdkProjectOptions & awscdk.AwsCdkTypeScriptAppOptions =\n merge(defaultOptions, userOptions);\n\n super(options);\n\n /**\n * Use catalog version for @types/node so all packages share a single\n * pinned version.\n */\n this.addDevDeps(\"@types/node@catalog:\");\n\n /**\n * Exclude test files from the main tsconfig only (not tsconfig.dev) so\n * tsc --build compiles only library code (avoids pulling in test-runner\n * types e.g. Vitest/Vite). ESLint and tests still use tsconfig.dev which\n * includes test files.\n */\n this.tsconfig?.addExclude(\"**/*.test.*\");\n this.tsconfig?.addExclude(\"**/*.spec.*\");\n\n /**\n * When using Jest, remove ts-jest since we use @swc/jest.\n * When using Vitest, add the Vitest component (test task + config + deps).\n */\n if (testRunner === TestRunner.VITEST) {\n new Vitest(this, {\n config: {\n include: [\"src/**/*.{test,spec}.?(c|m)[jt]s?(x)\"],\n ...options.vitestOptions?.config,\n },\n ...options.vitestOptions,\n });\n } else {\n this.deps.removeDependency(\"ts-jest\");\n }\n\n /**\n * Specify package manager in package.json.\n */\n this.package.file.addOverride(\n \"packageManager\",\n `pnpm@${options.pnpmVersion}`,\n );\n\n /**\n * Allow test files to use devDependencies. Projen disables the rule for\n * `tests/*` only; we colocate tests next to source so we extend it.\n */\n this.eslint?.addOverride({\n files: [\"**/*.test.*\", \"**/*.spec.*\"],\n rules: {\n \"import/no-extraneous-dependencies\": \"off\",\n },\n });\n\n /**\n * Some standard ignores for all projects.\n */\n this.gitignore?.addPatterns(\".DS_Store\", \"test-reports\", \"cdk.out\");\n this.npmignore?.addPatterns(\"*.spec.*\", \"*.test.*\", \"__fixtures__\");\n\n /**\n * Always create the AwsDeploymentConfig so the synth task is rewritten\n * consistently. AwsDeploymentTarget instances will register themselves\n * onto this config below.\n */\n new AwsDeploymentConfig(this);\n\n /**\n * Wire up deployment targets supplied via constructor options.\n */\n (options.deploymentTargets ?? []).forEach((targetOptions) =>\n this.addDeploymentTarget(targetOptions),\n );\n\n /**\n * Wire up deploy workflows. If `deployWorkflows` is undefined, derive one\n * workflow per unique awsStageType present in the deployment targets.\n * An explicit empty array opts out of auto-derivation.\n */\n const targetsForAutoDerive =\n AwsDeploymentConfig.of(this)?.awsDeploymentTargets ?? [];\n const deployWorkflows =\n options.deployWorkflows ??\n Array.from(new Set(targetsForAutoDerive.map((t) => t.awsStageType))).map(\n (awsStageType): DeployWorkflowOptions => ({\n awsStageType,\n buildWorkflow: options.sharedBuildWorkflow,\n }),\n );\n deployWorkflows.forEach(\n (workflowOptions) => new AwsDeployWorkflow(this, workflowOptions),\n );\n\n /**\n * Optional teardown workflow. Attached to the parent MonorepoProject so\n * it renders once per repo regardless of how many AwsCdkProjects exist.\n */\n if (options.teardownWorkflow) {\n new AwsTeardownWorkflow(parent, options.teardownWorkflow);\n }\n\n /**\n * If turbo is active in the parent project, configure it here.\n */\n const turboActive = TurboRepo.of(parent) !== undefined;\n if (turboActive) {\n const turbo = new TurboRepo(this);\n // `compileTask` is inactive for awscdk apps (no steps), so push CDK\n // build artifacts onto post-compile outputs where they actually render.\n turbo.postCompileTask?.outputs.push(\"dist/**\");\n turbo.postCompileTask?.inputs.push(\"src/**\");\n }\n\n /**\n * AI agent configuration — opt-in per project. Does not propagate from\n * the parent MonorepoProject so sub-projects don't render duplicate\n * `.cursor/` / `.claude/` / `CLAUDE.md` files into their own outdir.\n */\n if (\n options.agentConfig === true ||\n typeof options.agentConfig === \"object\"\n ) {\n new AgentConfig(\n this,\n typeof options.agentConfig === \"object\" ? options.agentConfig : {},\n );\n }\n\n /**\n * Add reset task if enabled.\n */\n if (options.resetTask !== false) {\n const defaultResetTaskOptions: ResetTaskOptions = {\n pathsToRemove: [\n \"node_modules\",\n \"dist\",\n \"lib\",\n \"cdk.out\",\n \"coverage\",\n \"test-reports\",\n \".turbo\",\n \"tsconfig.tsbuildinfo\",\n this.artifactsDirectory,\n ],\n };\n const userResetTaskOptions = options.resetTaskOptions ?? {};\n const resetTaskOptions: ResetTaskOptions = merge(\n defaultResetTaskOptions,\n {\n ...userResetTaskOptions,\n pathsToRemove: [\n ...(defaultResetTaskOptions.pathsToRemove ?? []),\n ...(userResetTaskOptions.pathsToRemove ?? []),\n ],\n },\n );\n new ResetTask(this, resetTaskOptions);\n }\n\n /**\n * Route dependency installation through the parent MonorepoProject so the\n * workspace install handles everything in one pass.\n */\n /* @ts-ignore access private method */\n const originalResolve = this.package.resolveDepsAndWritePackageJson;\n /* @ts-ignore access private method */\n this.package.installDependencies = () => {\n parent.requestInstallDependencies({\n resolveDepsAndWritePackageJson: () =>\n originalResolve.apply(this.package),\n });\n };\n /* @ts-ignore access private method */\n this.package.resolveDepsAndWritePackageJson = () => {};\n }\n\n /**\n * Add an AWS deployment target to this project after construction. The\n * target is registered on the existing `AwsDeploymentConfig` and immediately\n * available for `AwsDeployWorkflow` consumption.\n */\n public addDeploymentTarget(\n options: AwsDeploymentTargetOptions,\n ): AwsDeploymentTarget {\n return new AwsDeploymentTarget(this, options);\n }\n}\n","// eslint-disable-next-line import/no-extraneous-dependencies\nimport {\n AWS_STAGE_TYPE,\n AwsStageType,\n DEPLOYMENT_TARGET_ROLE,\n DeploymentTargetRoleType,\n} from \"@codedrifters/utils\";\nimport { Component } from \"projen\";\nimport { AwsCdkTypeScriptApp } from \"projen/lib/awscdk\";\nimport { BuildWorkflow, BuildWorkflowOptions } from \"projen/lib/build\";\nimport { GitHub, WorkflowSteps } from \"projen/lib/github\";\nimport { JobPermission, JobStep } from \"projen/lib/github/workflows-model\";\nimport { ValueOf } from \"type-fest\";\nimport { AwsDeploymentConfig } from \"../aws\";\nimport { addBuildCompleteJob } from \"./build-complete-job\";\nimport { AwsDeploymentTarget } from \"../aws/aws-deployment-target\";\nimport { GitBranch } from \"../git\";\nimport { MonorepoProject } from \"../projects\";\nimport { ROOT_CI_TASK_NAME, TurboRepo } from \"../turbo\";\nimport { VERSION } from \"../versions\";\n\nexport const PROD_DEPLOY_NAME = \"prod-deploy\";\n\nexport interface DeployWorkflowOptions {\n /**\n * What type of deploy is this workflow for?\n *\n * @default AWS_STAGE_TYPE.DEV\n */\n readonly awsStageType?: ValueOf<typeof AWS_STAGE_TYPE>;\n\n /**\n * Optionally feed a list of targets to deploy to.\n *\n * @default discovers all targets using stageType\n */\n readonly awsDeploymentTargets?: Array<AwsDeploymentTarget>;\n\n /**\n * Existing workflow, useful if we're tacking deployments onto an existing\n * build workflow\n */\n readonly buildWorkflow?: BuildWorkflow;\n\n /**\n * Options for the build workflow, if no build workflow is provided.\n */\n readonly buildWorkflowOptions?: Partial<BuildWorkflowOptions>;\n\n /**\n * Projects that should complete deployment before this one starts.\n */\n readonly deployAfterTargets?: Array<AwsDeploymentTarget>;\n}\n\nexport class AwsDeployWorkflow extends Component {\n public static of(\n project: AwsCdkTypeScriptApp,\n buildWorkflow: BuildWorkflow,\n ): AwsDeployWorkflow | undefined {\n const isDefined = (c: Component): c is AwsDeployWorkflow =>\n c instanceof AwsDeployWorkflow && c.buildWorkflow === buildWorkflow;\n return project.components.find(isDefined);\n }\n\n /**\n * The root project for this deploy workflow. Must be a monorepo project.\n */\n private rootProject: MonorepoProject;\n\n /**\n * What type of deploy is this workflow for?\n */\n public awsStageType: AwsStageType;\n\n /**\n * AWS environment type, such as primary or secondary.\n *\n * @deprecated Use deployment target role terminology elsewhere. This property is maintained for backward compatibility.\n * @default 'primary' (this is the only type supported currently)\n */\n public awsEnvironmentType: DeploymentTargetRoleType =\n DEPLOYMENT_TARGET_ROLE.PRIMARY;\n\n /**\n * The list of targets to deploy to.\n */\n readonly awsDeploymentTargets: Array<AwsDeploymentTarget>;\n\n /**\n * Hold the deploy workflow so we can add to it in preSynth\n */\n public buildWorkflow: BuildWorkflow;\n\n /**\n * Was this workflow created externally?\n */\n public externalWorkflow: boolean;\n\n /**\n * Projects that should complete deployment before this one starts.\n */\n public deployAfterTargets: Array<AwsDeploymentTarget>;\n\n constructor(\n public project: AwsCdkTypeScriptApp,\n public options: DeployWorkflowOptions = {},\n ) {\n super(project);\n\n /***************************************************************************\n *\n * Root project check\n *\n * Detect the root project and ensure it's of type MonorepoProject.\n *\n **************************************************************************/\n\n if (!(project.root instanceof MonorepoProject)) {\n throw new Error(\n \"AwsDeployWorkflow requires the root project to be a MonorepoProject\",\n );\n }\n\n this.rootProject = project.root;\n\n /***************************************************************************\n *\n * GitHub Check\n *\n * Make sure github config is active in the project. This is to ensure all\n * workflows will be output properly during synth.\n *\n **************************************************************************/\n\n const github = GitHub.of(this.rootProject);\n\n if (!github) {\n throw new Error(\n \"AwsDeployWorkflow requires a GitHub component in the root project\",\n );\n }\n\n /***************************************************************************\n *\n * TurboRepo Check\n *\n * If turbo is enabled, we may need the options later in this file.\n *\n **************************************************************************/\n\n const turbo = TurboRepo.of(this.rootProject);\n const buildWorkflowOptions: Partial<BuildWorkflowOptions> =\n turbo?.remoteCacheOptions\n ? TurboRepo.buildWorkflowOptions(turbo.remoteCacheOptions)\n : {};\n\n /***************************************************************************\n *\n * Workflow Deploy Type\n *\n * What type of environments are we deploying into? We'll default to dev to\n * be safe.\n *\n **************************************************************************/\n\n this.awsStageType = options.awsStageType ?? AWS_STAGE_TYPE.DEV;\n\n /***************************************************************************\n *\n * Workflow Deploy Targets\n *\n * Use provided targets or discover them based on the deploy type. Only\n * include targets that are marked for CI/CD.\n *\n **************************************************************************/\n\n this.awsDeploymentTargets =\n options.awsDeploymentTargets ??\n AwsDeploymentConfig.of(project)?.awsDeploymentTargets.filter(\n (target) =>\n target.awsStageType === this.awsStageType && target.ciDeployment,\n ) ??\n [];\n\n this.deployAfterTargets = options.deployAfterTargets ?? [];\n\n /***************************************************************************\n *\n * Build Workflow Options\n *\n * Can't use the options if an existing workflow was passed in.\n *\n **************************************************************************/\n\n if (options.buildWorkflow && options.buildWorkflowOptions) {\n throw new Error(\n \"Cannot provide both buildWorkflow and buildWorkflowOptions\",\n );\n }\n\n this.externalWorkflow = !!options.buildWorkflow;\n\n /***************************************************************************\n *\n * Build Workflow\n *\n * Create a workflow either based on input or from scratch.\n *\n **************************************************************************/\n\n this.buildWorkflow =\n options.buildWorkflow ??\n new BuildWorkflow(this.rootProject, {\n /**\n * Name based on project and environment.\n */\n name:\n options.buildWorkflowOptions?.name ??\n [\n \"deploy\",\n project.name,\n this.awsStageType,\n this.awsEnvironmentType,\n ].join(\"-\"),\n\n /**\n * Use the root projects build task.\n */\n buildTask: this.rootProject.buildTask,\n\n /**\n * Use push triggers based n the branch config for each environment.\n */\n workflowTriggers: {\n push: {\n branches: [\n ...this.awsDeploymentTargets.flatMap((t) =>\n t.branches.map((b) => b.branch),\n ),\n ],\n },\n workflowDispatch: {},\n ...options.buildWorkflowOptions?.workflowTriggers,\n },\n\n /**\n * Never allow mutations for deploys. This should have been handled\n * during build.\n */\n mutableBuild: false,\n\n /**\n * Do this pre-merge of permissions and build steps\n */\n ...options.buildWorkflowOptions,\n\n /**\n * Set GIT_BRANCH_NAME so Turborepo remote cache hashes match between local and CI.\n */\n env: {\n GIT_BRANCH_NAME: \"${{ github.head_ref || github.ref_name }}\",\n ...options.buildWorkflowOptions?.env,\n ...buildWorkflowOptions?.env,\n },\n\n /**\n * Some additional permissions may be required when turbo's involved.\n */\n permissions: {\n ...options.buildWorkflowOptions?.permissions,\n ...buildWorkflowOptions?.permissions,\n },\n\n /**\n * Assemble all pre-build steps\n */\n preBuildSteps: [\n ...this.setupPnpm(),\n ...this.setupNode(),\n {\n name: \"Install dependencies\",\n run: \"pnpm i --no-frozen-lockfile\",\n },\n ...(options.buildWorkflowOptions?.preBuildSteps ?? []),\n ...(buildWorkflowOptions?.preBuildSteps ?? []),\n ],\n });\n\n /***************************************************************************\n *\n * Add Deployments to workflow\n *\n **************************************************************************/\n\n const buildJobName = (target: AwsDeploymentTarget) => {\n return [\n target.awsStageType,\n target.deploymentTargetRole,\n \"deploy\",\n target.project.name,\n target.account,\n target.region,\n ].join(\"-\");\n };\n\n this.awsDeploymentTargets.forEach((target) => {\n const deployJobName = buildJobName(target);\n\n // Build the branch filter condition\n const branchFilterCondition = this.buildBranchFilterCondition(\n target.branches,\n );\n\n // Combine with the existing build mutation check\n const jobCondition = branchFilterCondition\n ? \"${{ \" +\n [\n \"!needs.build.outputs.self_mutation_happened\",\n `(${branchFilterCondition})`,\n ].join(\" && \") +\n \" }}\"\n : \"${{ !needs.build.outputs.self_mutation_happened }}\";\n\n this.buildWorkflow.addPostBuildJob(deployJobName, {\n name: `Deploy ${this.project.name} ${target.awsStageType}/${target.deploymentTargetRole}/${target.account}/${target.region}`,\n needs: [\n \"build\",\n ...this.deployAfterTargets.map((p) => {\n return buildJobName(p);\n }),\n ],\n runsOn: [\"ubuntu-latest\"],\n permissions: {\n contents: JobPermission.READ,\n idToken: JobPermission.WRITE,\n },\n concurrency: deployJobName,\n if: jobCondition,\n steps: [...this.deploySteps(target)],\n });\n });\n\n /**\n * Append the \"complete\" gate job (ADR 0004) so this workflow has a single\n * required status check.\n */\n addBuildCompleteJob(this.buildWorkflow);\n }\n\n public setupNode = (): Array<JobStep> => {\n return [\n {\n name: \"Setup Node\",\n uses: `actions/setup-node@${VERSION.SETUP_NODE_ACTION_VERSION}`,\n with: {\n [\"node-version\"]: VERSION.NODE_WORKFLOWS,\n },\n // occasionally this step fails due to internal issues at github\n timeoutMinutes: 1,\n },\n ];\n };\n\n public setupPnpm = (): Array<JobStep> => {\n return [\n {\n name: \"Setup PNPM\",\n uses: `pnpm/action-setup@${VERSION.PNPM_ACTION_SETUP_VERSION}`,\n with: {\n version: VERSION.PNPM_VERSION,\n },\n },\n ];\n };\n\n /**\n * Builds a GitHub Actions condition string that checks if the current branch\n * matches any of the provided branch patterns.\n *\n * Handles both exact matches (e.g., \"main\") and glob patterns (e.g., \"feature/*\").\n * Also allows workflow_dispatch (manual runs) to proceed.\n *\n * @param branches Array of GitBranch objects with branch patterns\n * @returns Condition string or empty string if no branches provided\n */\n private buildBranchFilterCondition = (branches: Array<GitBranch>): string => {\n if (!branches || branches.length === 0) {\n return \"\";\n }\n\n const conditions: Array<string> = [];\n\n // Always allow workflow_dispatch (manual workflow runs)\n conditions.push(\"github.event_name == 'workflow_dispatch'\");\n\n for (const branch of branches) {\n const branchPattern = branch.branch;\n\n // Handle glob patterns (e.g., \"feature/*\")\n if (branchPattern.includes(\"*\")) {\n // Replace * with proper startsWith check\n const prefix = branchPattern.replace(/\\*.*$/, \"\");\n conditions.push(`startsWith(github.ref, 'refs/heads/${prefix}')`);\n // PR support, unprefixed branch names\n conditions.push(`startsWith(github.head_ref, '${prefix}')`);\n } else {\n // Exact match\n conditions.push(`github.ref == 'refs/heads/${branchPattern}'`);\n }\n }\n\n /**\n * Combine all conditions with OR\n */\n return conditions.join(\" || \");\n };\n\n private deploySteps = (target: AwsDeploymentTarget): Array<JobStep> => {\n const {\n awsStageType,\n deploymentTargetRole,\n account,\n region,\n ciDeploymentConfig,\n awsDeploymentConfig,\n } = target;\n const { roleArn, stackPattern } = ciDeploymentConfig ?? {};\n const { rootCdkOut } = awsDeploymentConfig;\n\n return [\n ...this.setupPnpm(),\n ...this.setupNode(),\n\n /**\n * Install CDK\n */\n {\n name: \"Install CDK\",\n run: \"pnpm add aws-cdk\",\n },\n\n /**\n * Configure AWS creds.\n */\n {\n name: `AWS Creds ${awsStageType}/${deploymentTargetRole}/${account}/${region}`,\n uses: \"aws-actions/configure-aws-credentials@v4\",\n with: {\n \"role-to-assume\": roleArn,\n \"aws-region\": region,\n \"role-duration-seconds\": 900, // 15 minutes\n },\n },\n\n /**\n * Run CDK Deploy\n */\n {\n name: `Deploy ${awsStageType}/${deploymentTargetRole}/${account}/${region}`,\n run: `pnpm dlx aws-cdk deploy --no-rollback --require-approval=never --app=${rootCdkOut} \"${stackPattern}\"`,\n },\n ];\n };\n\n preSynthesize(): void {\n /**\n * Ensure turbo is active when needed.\n */\n if (!this.externalWorkflow && TurboRepo.of(this.rootProject)) {\n this.buildWorkflow.addPostBuildSteps(\n {\n name: \"Build Sub Projects\",\n run: `npx projen ${ROOT_CI_TASK_NAME}`,\n },\n WorkflowSteps.uploadArtifact({\n name: \"Upload Turbo runs\",\n if: \"always()\",\n continueOnError: true,\n with: {\n name: \"turbo-runs\",\n path: \".turbo/runs\",\n },\n }),\n );\n }\n\n super.preSynthesize();\n }\n}\n","import { Component } from \"projen\";\nimport { GitHub, GithubWorkflow } from \"projen/lib/github\";\nimport { JobPermission } from \"projen/lib/github/workflows-model\";\nimport { AwsDeploymentTarget } from \"../aws/aws-deployment-target\";\nimport { MonorepoProject } from \"../projects/monorepo-project\";\n\n/**\n * Default branch-delete patterns that trigger the teardown workflow.\n */\nexport const DEFAULT_TEARDOWN_BRANCH_PATTERNS: ReadonlyArray<string> = [\n \"feat/*\",\n \"fix/*\",\n \"feature/*\",\n];\n\n/**\n * Options for {@link AwsTeardownWorkflow}.\n */\nexport interface AwsTeardownWorkflowOptions {\n /**\n * Targets to scan for orphaned CloudFormation stacks.\n */\n readonly awsDestructionTargets: Array<AwsDeploymentTarget>;\n\n /**\n * Name of the tag containing the repo name. Used to find CloudFormation\n * stacks associated with this repo.\n */\n readonly repoTagName: string;\n\n /**\n * Name of the tag containing the stage type (e.g. dev, stage, prod).\n */\n readonly stageTypeTagName: string;\n\n /**\n * Name of the tag containing the environment type (e.g. primary, secondary).\n */\n readonly environmentTypeTagName: string;\n\n /**\n * Name of the tag where branch names are stored. Used to determine if a\n * stack is orphaned (no matching branch).\n */\n readonly branchNameTagName: string;\n\n /**\n * Branch patterns whose deletion triggers the teardown workflow.\n *\n * @default [\"feat/*\", \"fix/*\", \"feature/*\"]\n */\n readonly deleteBranchPatterns?: Array<string>;\n}\n\n/**\n * Resolve the set of branch-delete patterns to wire into the workflow's\n * `on.delete.branches` trigger.\n *\n * Precedence:\n * 1. Explicit `deleteBranchPatterns` from options.\n * 2. Wildcard patterns (containing `*`) derived from the destruction\n * targets' configured branches, deduped.\n * 3. {@link DEFAULT_TEARDOWN_BRANCH_PATTERNS} as a last-resort fallback.\n */\nconst resolveBranchPatterns = (\n explicit: Array<string> | undefined,\n targets: ReadonlyArray<AwsDeploymentTarget>,\n): Array<string> => {\n if (explicit && explicit.length > 0) {\n return [...explicit];\n }\n\n const derived = Array.from(\n new Set(\n targets\n .flatMap((target) => target.branches.map((b) => b.branch))\n .filter((branch): branch is string => typeof branch === \"string\")\n .filter((branch) => branch.includes(\"*\")),\n ),\n );\n\n if (derived.length > 0) {\n return derived;\n }\n\n return [...DEFAULT_TEARDOWN_BRANCH_PATTERNS];\n};\n\n/**\n * Scheduled GitHub Actions workflow that tears down orphaned CloudFormation\n * stacks whose associated branch no longer exists.\n */\nexport class AwsTeardownWorkflow extends Component {\n constructor(\n public rootProject: MonorepoProject,\n options: AwsTeardownWorkflowOptions,\n ) {\n super(rootProject);\n\n const {\n awsDestructionTargets,\n repoTagName,\n stageTypeTagName,\n environmentTypeTagName,\n branchNameTagName,\n deleteBranchPatterns,\n } = options;\n\n if (!repoTagName) {\n throw new Error(\"AwsTeardownWorkflow requires `repoTagName`\");\n }\n if (!stageTypeTagName) {\n throw new Error(\"AwsTeardownWorkflow requires `stageTypeTagName`\");\n }\n if (!environmentTypeTagName) {\n throw new Error(\"AwsTeardownWorkflow requires `environmentTypeTagName`\");\n }\n if (!branchNameTagName) {\n throw new Error(\"AwsTeardownWorkflow requires `branchNameTagName`\");\n }\n\n if (!(rootProject instanceof MonorepoProject)) {\n throw new Error(\n \"AwsTeardownWorkflow requires the root project to be a MonorepoProject\",\n );\n }\n\n const github = GitHub.of(this.rootProject);\n\n if (!github) {\n throw new Error(\n \"AwsTeardownWorkflow requires a GitHub component in the root project\",\n );\n }\n\n const branchPatterns = resolveBranchPatterns(\n deleteBranchPatterns,\n awsDestructionTargets,\n );\n\n const workflow = new GithubWorkflow(github, \"teardown-dev\");\n workflow.on({\n workflowDispatch: {},\n schedule: [\n {\n cron: \"32 6 * * *\",\n },\n ],\n delete: {\n branches: branchPatterns,\n },\n });\n\n awsDestructionTargets.forEach((target) => {\n const {\n awsStageType,\n deploymentTargetRole,\n account,\n region,\n ciDeploymentConfig,\n } = target;\n const { roleArn } = ciDeploymentConfig ?? {};\n\n workflow.addJob(\n `teardown-${awsStageType}-${deploymentTargetRole}-${account}-${region}`.toLowerCase(),\n {\n name: `Teardown Stacks in ${awsStageType}/${deploymentTargetRole}/${account}/${region}`,\n runsOn: [\"ubuntu-latest\"],\n permissions: {\n contents: JobPermission.READ,\n idToken: JobPermission.WRITE,\n },\n env: {\n REPO: \"${{ github.repository }}\",\n REGIONS: [region].join(\" \"),\n },\n steps: [\n {\n name: `AWS Creds ${account}/${region}`,\n uses: \"aws-actions/configure-aws-credentials@v6\",\n with: {\n \"role-to-assume\": roleArn,\n \"aws-region\": region,\n \"role-duration-seconds\": 900,\n },\n },\n {\n name: \"Fetch All Branches\",\n id: \"fetch_branches\",\n uses: \"actions/github-script@v9\",\n with: {\n script: [\n \"const all = await github.paginate(github.rest.repos.listBranches, {\",\n \" owner: context.repo.owner,\",\n \" repo: context.repo.repo,\",\n \" per_page: 100\",\n \"});\",\n \"const names = all.map(b => b.name);\",\n \"console.log(`Found branches: ${names}`);\",\n 'core.setOutput(\"json\", JSON.stringify(names));',\n ].join(\"\\n\"),\n },\n },\n {\n name: \"Save Branches to File\",\n run: [\n 'echo \"Saving branches to file\"',\n \"echo '${{ steps.fetch_branches.outputs.json }}' | jq -r '.[]' | sort -u > branches.txt\",\n 'echo \"Branches:\"',\n \"cat branches.txt\",\n ].join(\"\\n\"),\n },\n {\n name: \"Find Stacks by Tag\",\n id: \"find_stacks\",\n run: [\n \"set -euo pipefail\",\n \": > candidates.txt # columns: arn region branchTag\",\n \"# Build tag filters\",\n `TAG_FILTERS=( \"Key=${repoTagName},Values=$REPO\" )`,\n `TAG_FILTERS+=( \"Key=${stageTypeTagName},Values=${awsStageType}\" )`,\n `TAG_FILTERS+=( \"Key=${environmentTypeTagName},Values=${deploymentTargetRole}\" )`,\n \"for r in $REGIONS; do\",\n ` echo \"Scanning region: $r\"`,\n \" aws resourcegroupstaggingapi get-resources \\\\\",\n ' --region \"$r\" \\\\',\n ' --resource-type-filters \"cloudformation:stack\" \\\\',\n ' --tag-filters \"${TAG_FILTERS[@]}\" \\\\',\n ` | jq -r --arg r \"$r\" '`,\n \" .ResourceTagMappingList[]\",\n \" | . as $res\",\n ` | ($res.Tags[] | select(.Key==\"${branchNameTagName}\") | .Value) as $branch`,\n ' | [$res.ResourceARN, $r, ($branch // \"\")]',\n \" | @tsv\",\n \" ' >> candidates.txt\",\n \"done\",\n \"echo 'Tagged stacks:'\",\n `(echo -e \"ARN\\\\tREGION\\\\tBRANCH\"; cat candidates.txt) | column -t -s $'\\\\t'`,\n ].join(\"\\n\"),\n },\n {\n name: \"Determine Orphan Stacks (No Matching Branch)\",\n run: [\n \"set -euo pipefail\",\n \": > orphans.txt # arn region branch\",\n \"while IFS=$'\\\\t' read -r arn region branch; do\",\n ' [ -z \"$arn\" ] && continue',\n ' if [ -z \"$branch\" ]; then',\n \" # If no Branch tag, treat as not-a-preview; skip\",\n \" continue\",\n \" fi\",\n ' if ! grep -Fxq \"$branch\" branches.txt; then',\n ' echo -e \"$arn\\\\t$region\\\\t$branch\" >> orphans.txt',\n \" fi\",\n \"done < candidates.txt\",\n \"\",\n \"if [ -s orphans.txt ]; then\",\n ' echo \"Orphan stacks (no matching branch):\"',\n \" (echo -e \\\"ARN\\\\tREGION\\\\tBRANCH\\\"; cat orphans.txt) | column -t -s $'\\\\t'\",\n \"else\",\n ' echo \"No orphan stacks found.\"',\n \"fi\",\n ].join(\"\\n\"),\n },\n {\n name: \"Delete Orphan Stacks\",\n if: \"hashFiles('orphans.txt') != ''\",\n run: [\n \"set -euo pipefail\",\n \"while IFS=$'\\\\t' read -r arn region branch; do\",\n ' [ -z \"$arn\" ] && continue',\n \" stack_name=$(cut -d'/' -f2 <<<\\\"$arn\\\")\",\n ' echo \"Deleting $stack_name (branch=$branch) in $region\"',\n ' aws cloudformation delete-stack --region \"$region\" --stack-name \"$stack_name\" || true',\n \"done < orphans.txt\",\n ].join(\"\\n\"),\n },\n ],\n },\n );\n });\n }\n}\n","import { SampleFile } from \"projen\";\nimport { AstroIntegrationSpec } from \"../astro/astro-config-options\";\nimport { TurboRepo } from \"../turbo\";\nimport { VERSION } from \"../versions\";\nimport { AstroProject, AstroProjectOptions } from \"./astro-project\";\n\n/**\n * A single Starlight social icon link.\n */\nexport interface StarlightSocialLink {\n readonly icon: string;\n readonly label: string;\n readonly href: string;\n}\n\n/**\n * Starlight logo configuration.\n */\nexport interface StarlightLogo {\n readonly src: string;\n readonly alt?: string;\n}\n\n/**\n * Starlight edit-link configuration.\n */\nexport interface StarlightEditLink {\n readonly baseUrl: string;\n}\n\n/**\n * Sidebar item accepted by Starlight's `sidebar` config. Covers the four\n * common shapes: link, group with nested items, autogenerated group, and\n * internal slug reference.\n */\nexport type StarlightSidebarItem =\n | {\n readonly label: string;\n readonly link: string;\n readonly badge?:\n | string\n | { readonly text: string; readonly variant?: string };\n }\n | {\n readonly label: string;\n readonly items: ReadonlyArray<StarlightSidebarItem>;\n }\n | {\n readonly label: string;\n readonly autogenerate: {\n readonly directory: string;\n readonly collapsed?: boolean;\n };\n }\n | { readonly label: string; readonly slug: string };\n\n/**\n * Configuration options for StarlightProject.\n */\nexport interface StarlightProjectOptions extends AstroProjectOptions {\n /**\n * Starlight site title (required).\n */\n readonly starlightTitle: string;\n\n /**\n * Starlight site description.\n */\n readonly starlightDescription?: string;\n\n /**\n * Social links rendered in the Starlight header.\n */\n readonly social?: ReadonlyArray<StarlightSocialLink>;\n\n /**\n * Sidebar config (passed through verbatim). When omitted, Starlight\n * autogenerates the sidebar from the `src/content/docs/` tree.\n */\n readonly sidebar?: ReadonlyArray<StarlightSidebarItem>;\n\n /**\n * Custom CSS files loaded by Starlight.\n */\n readonly customCss?: ReadonlyArray<string>;\n\n /**\n * Site logo displayed in the Starlight header.\n */\n readonly logo?: StarlightLogo;\n\n /**\n * \"Edit this page\" link configuration.\n */\n readonly editLink?: StarlightEditLink;\n\n /**\n * @astrojs/starlight package version.\n *\n * @default VERSION.STARLIGHT_VERSION\n */\n readonly starlightVersion?: string;\n\n /**\n * sharp package version (required peer for Starlight's image pipeline).\n *\n * @default VERSION.SHARP_VERSION\n */\n readonly sharpVersion?: string;\n\n /**\n * Emit sample Starlight content (`src/content/docs/index.mdx`,\n * `src/content/config.ts`).\n *\n * @default false\n */\n readonly sampleContent?: boolean;\n}\n\n/**\n * Docs site scaffolded on top of {@link AstroProject} using the\n * Starlight Astro integration.\n */\nexport class StarlightProject extends AstroProject {\n constructor(userOptions: StarlightProjectOptions) {\n const starlightConfig = buildStarlightConfig(userOptions);\n const starlightSpec: AstroIntegrationSpec = {\n name: \"starlight\",\n importPath: \"@astrojs/starlight\",\n defaultImport: true,\n args: JSON.stringify(starlightConfig, null, 2),\n };\n\n /**\n * Prepend the Starlight integration so it appears first in the\n * rendered `integrations` array (matches Starlight docs convention).\n */\n /**\n * Exclude Starlight and sharp from projen's per-package ncu upgrade\n * workflow — same pattern AstroProject uses for `astro` — so\n * VERSION.STARLIGHT_VERSION / VERSION.SHARP_VERSION remain the single\n * source of truth.\n */\n const mergedOptions: AstroProjectOptions = {\n ...userOptions,\n integrations: [starlightSpec, ...(userOptions.integrations ?? [])],\n depsUpgradeOptions: {\n ...userOptions.depsUpgradeOptions,\n exclude: [\n ...(userOptions.depsUpgradeOptions?.exclude ?? []),\n \"@astrojs/starlight\",\n \"sharp\",\n ],\n },\n };\n\n super(mergedOptions);\n\n const starlightVersion =\n userOptions.starlightVersion ?? VERSION.STARLIGHT_VERSION;\n const sharpVersion = userOptions.sharpVersion ?? VERSION.SHARP_VERSION;\n\n this.addDeps(\n `@astrojs/starlight@${starlightVersion}`,\n `sharp@${sharpVersion}`,\n );\n\n /**\n * Extend turbo compile inputs with Starlight's content collection tree.\n */\n const turbo = TurboRepo.of(this);\n if (turbo?.compileTask) {\n turbo.compileTask.inputs.push(\"src/content/**\");\n }\n\n /**\n * Optional sample content.\n */\n if (userOptions.sampleContent === true) {\n new SampleFile(this, \"src/content/docs/index.mdx\", {\n contents: DEFAULT_INDEX_MDX,\n });\n new SampleFile(this, \"src/content/config.ts\", {\n contents: DEFAULT_CONTENT_CONFIG_TS,\n });\n }\n }\n}\n\n/**\n * Build the JSON-serializable Starlight config object from user options.\n */\nfunction buildStarlightConfig(\n options: StarlightProjectOptions,\n): Record<string, unknown> {\n const config: Record<string, unknown> = {\n title: options.starlightTitle,\n };\n if (options.starlightDescription !== undefined) {\n config.description = options.starlightDescription;\n }\n if (options.social !== undefined) {\n config.social = options.social;\n }\n if (options.sidebar !== undefined) {\n config.sidebar = options.sidebar;\n }\n if (options.customCss !== undefined) {\n config.customCss = options.customCss;\n }\n if (options.logo !== undefined) {\n config.logo = options.logo;\n }\n if (options.editLink !== undefined) {\n config.editLink = options.editLink;\n }\n return config;\n}\n\nconst DEFAULT_INDEX_MDX = `---\ntitle: Welcome\ndescription: Starlight-powered documentation site.\n---\n\n# Hello, Starlight!\n\nEdit \\`src/content/docs/index.mdx\\` to replace this page.\n`;\n\nconst DEFAULT_CONTENT_CONFIG_TS = `import { defineCollection } from \"astro:content\";\nimport { docsSchema } from \"@astrojs/starlight/schema\";\n\nexport const collections = {\n docs: defineCollection({ schema: docsSchema() }),\n};\n`;\n","import { relative } from \"node:path\";\nimport { Component } from \"projen\";\nimport { TypeScriptProject } from \"projen/lib/typescript\";\nimport { ensureRelativePathStartsWithDot } from \"projen/lib/util/path\";\n\n/*******************************************************************************\n *\n * Update / customize typescript configs for a project.\n *\n * Update typescript paths in tsconfig so we don't have to compile packages to\n * dist in order to see changes.\n *\n ******************************************************************************/\nexport class TypeScriptConfig extends Component {\n constructor(project: TypeScriptProject) {\n super(project);\n\n /**\n * Container for paths to insert at the end.\n */\n let tsPaths = {};\n\n const workspaceDeps = project.deps.all.filter(\n (d) => d.version === \"workspace:*\",\n );\n\n workspaceDeps.forEach((dep) => {\n const subproject = (\n project.root.subprojects as Array<TypeScriptProject>\n ).find((p) => p.package.packageName === dep.name);\n\n if (!subproject) {\n throw new Error(`Could not find subproject ${dep.name} in monorepo.`);\n }\n\n tsPaths = {\n ...tsPaths,\n [dep.name]: [\n ensureRelativePathStartsWithDot(\n relative(project.outdir, subproject.outdir),\n ),\n ],\n };\n });\n\n project.tsconfig?.file.addOverride(\"compilerOptions.paths\", tsPaths);\n project.tsconfigDev?.file.addOverride(\"compilerOptions.paths\", tsPaths);\n }\n}\n"],"mappings":"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ACA;AAAA,QACA;AAAA,QACA;AAAA,QACA;AAAA,QACA;AAAA,QACA;AAAA,QACA;AAAA,QACA;AAAA,QACA;AAAA,QACA;AAAA,QACA;AAAA,QACA;AAAA,QACA;AAAA,QACA;AAAA,QACA;AAAA,QACA;AAAA,QACA;AAAA,QACA;AAAA,QACA;AAAA,QACA;AAAA,QACA;AAAA,QACA;AAAA,QACA;AAAA,QACA;AAAA,QACA;AAAA,QACA;AAAA,QACA;AAAA,QACA;AAAA,QACA;AAAA,QACA;AAAA,QACA;AAAA,QACA;AAAA,QACA;AAAA,QACA;AAAA,QACA;AAAA,QACA;AAAA,QACA;AAAA,QACA;AAAA,QACA;AAAA,QACA;AAAA,QACA;AAAA,QACA;AAAA,QACA;AAAA,QACA;AAAA,QACA;AAAA,QACA;AAAA,QACA;AAAA,QACA;AAAA,QACA;AAAA,QACA;AAAA,QACA;AAAA,QACA;AAAA,QACA;AAAA,QACA;AAAA,QACA;AAAA,QACA;AAAA,QACA;AAAA,QACA;AAAA,QACA;AAAA,QACA;AAAA,QACA;AAAA,QACA;AAAA,QACA;AAAA,QACA;AAAA,QACA;AAAA,QACA;AAAA,QACA;AAAA,QACA;AAAA,QACA;AAAA,QACA;AAAA,QACA;AAAA,QACA;AAAA,QACA;AAAA,QACA;AAAA,QACA;AAAA,QACA;AAAA,QACA;AAAA,QACA;AAAA,QACA;AAAA,QACA;AAAA,QACA;AAAA,QACA;AAAA,QACA;AAAA,QACA;AAAA,QACA;AAAA,QACA;AAAA,QACA;AAAA,QACA;AAAA,QACA;AAAA,QACA;AAAA,QACA;AAAA,QACA;AAAA,QACA;AAAA,QACA;AAAA,QACA;AAAA,QACA;AAAA,QACA;AAAA,QACA;AAAA,QACA;AAAA,QACA;AAAA,QACA;AAAA,QACA;AAAA,QACA;AAAA,QACA;AAAA,QACA;AAAA,QACA;AAAA,QACA;AAAA,QACA;AAAA,QACA;AAAA,QACA;AAAA,QACA;AAAA,QACA;AAAA,QACA;AAAA,QACA;AAAA,QACA;AAAA,QACA;AAAA,MACF,EAAE,KAAK,IAAI;AAAA,MACX,MAAM,CAAC,U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AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;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IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,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ACA;AAAA,QACA;AAAA,QACA;AAAA,QACA;AAAA,QACA;AAAA,QACA;AAAA,QACA;AAAA,QACA;AAAA,QACA;AAAA,QACA;AAAA,QACA;AAAA,QACA;AAAA,QACA;AAAA,QACA;AAAA,QACA;AAAA,QACA;AAAA,QACA;AAAA,QACA;AAAA,QACA;AAAA,QACA;AAAA,QACA;AAAA,QACA;AAAA,QACA;AAAA,QACA;AAAA,QACA;AAAA,QACA;AAAA,QACA;AAAA,QACA;AAAA,QACA;AAAA,QACA;AAAA,QACA;AAAA,QACA;AAAA,QACA;AAAA,QACA;AAAA,QACA;AAAA,QACA;AAAA,QACA;AAAA,QACA;AAAA,QACA;AAAA,QACA;AAAA,QACA;AAAA,QACA;AAAA,QACA;AAAA,QACA;AAAA,QACA;AAAA,QACA;AAAA,QACA;AAAA,QACA;AAAA,QACA;AAAA,QACA;AAAA,QACA;AAAA,QACA;AAAA,QACA;AAAA,QACA;AAAA,QACA;AAAA,QACA;AAAA,QACA;AAAA,QACA;AAAA,QACA;AAAA,QACA;AAAA,QACA;AAAA,QACA;AAAA,QACA;AAAA,QACA;AAAA,QACA;AAAA,QACA;AAAA,QACA;AAAA,QACA;AAAA,MACF,EAAE,KAAK,IAAI;AAAA,MACX,MAAM,CAAC,UAAU;AAAA,IACnB;AAAA,IACA;AAAA,MACE,MAAM;AAAA,MACN,aAAa;AAAA,MACb,OAAO,iBAAiB;AAAA,MACxB,SAAS;AAAA,QACP;AAAA,QACA;AAAA,QACA;AAAA,QACA;AAAA,QACA;AAAA,QACA;AAAA,QACA;AAAA,QACA;AAAA,QACA;AAAA,QACA;AAAA,QACA;AAAA,QACA;AAAA,QACA;AAAA,QACA;AAAA,QACA;AAAA,QACA;AAAA,QACA;AAAA,QACA;AAAA,QACA;AAAA,QACA;AAAA,QACA;AAAA,QACA;AAAA,QACA;AAAA,QACA;AAAA,QACA;AAAA,QACA;AAAA,QACA;AAAA,QACA;AAAA,QACA;AAAA,QACA;AAAA,QACA;AAAA,QACA;AAAA,QACA;AAAA,QACA;AAAA,QACA;AAAA,QACA;AAAA,MACF,EAAE,KAAK,IAAI;AAAA,MACX,MAAM,CAAC,UAAU;AAAA,IACnB;AAAA,EACF;AACF;;;ACzIA,IAAM,mCAAkD;AAAA,EACtD,MAAM;AAAA,EACN,aACE;AAAA,EACF,OAAO,YAAY;AAAA,EACnB,UAAU;AAAA,EACV,WAAW,EAAE,QAAQ,EAAE,SAAS,KAAK,EAAE;AAAA,EACvC,QAAQ;AAAA,IACN;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA,GAAG;AAAA,IACH;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IAC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AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;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,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,EACF,EAAE,KAAK,IAAI;AACb;AAGA,IAAM,sBAAkC;AAAA,EACtC,MAAM;AAAA,EACN,aACE;AAAA,EACF,wBAAwB;AAAA,EACxB,eAAe;AAAA,EACf,SAAS;AAAA,EACT,OAAO;AAAA,EACP,WAAW,EAAE,QAAQ,EAAE,SAAS,KAAK,EAAE;AAAA,EACvC,cAAc;AAAA,IACZ;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,EACF,EAAE,KAAK,IAAI;AACb;AAMO,IAAM,wBAAyC;AAAA,EACpD,MAAM;AAAA,EACN,aACE;AAAA,EACF,aAAa,MAAM;AAAA,EACnB,OAAO;AAAA,IACL;AAAA,MACE,MAAM;AAAA,MACN,aACE;AAAA,MACF,OAAO,iBAAiB;AAAA,MACxB,SAAS;AAAA,QACP;AAAA,QACA;AAAA,QACA;AAAA,QACA;AAAA,QACA;AAAA,QACA;AAAA,MACF,EAAE,KAAK,IAAI;AAAA,MACX,WAAW;AAAA,QACT,QAAQ,EAAE,SAAS,KAAK;AAAA,MAC1B;AAAA,MACA,MAAM,CAAC,UAAU;AAAA,IACnB;AAAA,EACF;AAAA,EACA,QAAQ,CAAC,mBAAmB;AAAA,EAC5B,WAAW,CAAC,sBAAsB;AAAA,EAClC,QAAQ;AAAA,IACN;AAAA,MACE,MAAM;AAAA,MACN,OAAO;AAAA,MACP,aAAa;AAAA,IACf;AAAA,IACA;AAAA,MACE,MAAM;AAAA,MACN,OAAO;AAAA,MACP,aAAa;AAAA,IACf;AAAA,IACA;AAAA,MACE,MAAM;AAAA,MACN,OAAO;AAAA,MACP,aAAa;AAAA,IACf;AAAA,IACA;AAAA,MACE,MAAM;AAAA,MACN,OAAO;AAAA,MACP,aACE;AAAA,IACJ;AAAA,EACF;AACF;;;AC9TA,IAAM,wBAAwC;AAAA,EAC5C,MAAM;AAAA,EACN,aACE;AAAA,EACF,SAAS;AAAA,IACP;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,EACF,EAAE,KAAK,IAAI;AACb;AAQA,IAAM,uBAAsC;AAAA,EAC1C,MAAM;AAAA,EACN,aACE;AAAA,EACF,OAAO,YAAY;AAAA,EACnB,UAAU;AAAA,EACV,WAAW,EAAE,QAAQ,EAAE,SAAS,KAAK,EAAE;AAAA,EACvC,QAAQ;AAAA,IACN;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA,GAAG;AAAA,IACH;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,EACF,EAAE,KAAK,IAAI;AACb;AAQA,IAAM,sBAAqC;AAAA,EACzC,MAAM;AAAA,EACN,aACE;AAAA,EACF,OAAO,YAAY;AAAA,EACnB,UAAU;AAAA,EACV,qBAAqB,CAAC;AAAA,EACtB,WAAW,EAAE,QAAQ,EAAE,SAAS,KAAK,EAAE;AAAA,EACvC,QAAQ;AAAA,IACN;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA,GAAG;AAAA,IACH;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,EACF,EAAE,KAAK,IAAI;AACb;AAQO,IAAM,qBAAsC;AAAA,EACjD,MAAM;AAAA,EACN,aACE;AAAA;AAAA,EAGF,aAAa,MAAM;AAAA,EAEnB,OAAO;AAAA,IACL;AAAA,MACE,MAAM;AAAA,MACN,aACE;AAAA,MACF,OAAO,iBAAiB;AAAA,MACxB,SAAS;AAAA,QACP;AAAA,QACA;AAAA,QACA;AAAA,QACA;AAAA,QACA;AAAA,QACA;AAAA,QACA;AAAA,QACA;AAAA,QACA;AAAA,QACA;AAAA,MACF,EAAE,KAAK,IAAI;AAAA,MACX,WAAW;AAAA,QACT,QAAQ,EAAE,QAAQ,YAAqB;AAAA,QACvC,QAAQ,EAAE,SAAS,KAAK;AAAA,MAC1B;AAAA,MACA,MAAM,CAAC,UAAU;AAAA,IACnB;AAAA,EACF;AAAA,EAEA,WAAW,CAAC,sBAAsB,mBAAmB;AAAA,EAErD,YAAY,CAAC,qBAAqB;AAAA,EAElC,mBAAmB;AAAA,IACjB,OAAO;AAAA;AAAA,MAEL;AAAA,IACF;AAAA,EACF;AACF;;;ACzwBA,IAAM,+BAA8C;AAAA,EAClD,MAAM;AAAA,EACN,aACE;AAAA,EACF,OAAO,YAAY;AAAA,EACnB,UAAU;AAAA,EACV,WAAW,EAAE,QAAQ,EAAE,SAAS,KAAK,EAAE;AAAA,EACvC,QAAQ;AAAA,IACN;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA,GAAG;AAAA,IACH;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AA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AAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,EACF,EAAE,KAAK,IAAI;AACb;AAQA,IAAM,gBAA4B;AAAA,EAChC,MAAM;AAAA,EACN,aACE;AAA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;AAAA,QACA;AAAA,QACA;AAAA,QACA;AAAA,QACA;AAAA,QACA;AAAA,QACA;AAAA,QACA;AAAA,QACA;AAAA,QACA;AAAA,QACA;AAAA,QACA;AAAA,QACA;AAAA,QACA;AAAA,QACA;AAAA,QACA;AAAA,QACA;AAAA,QACA;AAAA,QACA;AAAA,QACA;AAAA,QACA;AAAA,QACA;AAAA,QACA;AAAA,QACA;AAAA,QACA;AAAA,QACA;AAAA,QACA;AAAA,QACA;AAAA,QACA;AAAA,QACA;AAAA,QACA;AAAA,QACA;AAAA,QACA;AAAA,QACA;AAAA,QACA;AAAA,QACA;AAAA,QACA;AAAA,QACA;AAAA,QACA;AAAA,QACA;AAAA,QACA;AAAA,QACA;AAAA,QACA;AAAA,QACA;AAAA,QACA;AAAA,QACA;AAAA,QACA;AAAA,QACA;AAAA,QACA;AAAA,QACA;AAAA,QACA;AAAA,QACA;AAAA,QACA;AAAA,QACA;AAAA,QACA;AAAA,QACA;AAAA,QACA;AAAA,QACA;AAAA,QACA;AAAA,QACA;AAAA,QACA;AAAA,QACA;AAAA,QACA;AAAA,QACA;AAAA,QACA;AAAA,QACA;AAAA,QACA;AAAA,QACA;AAAA,QACA;AAAA,QACA;AAAA,QACA;AAAA,QACA;AAAA,QACA;AAAA,QACA;AAAA,QACA;AAAA,QACA;AAAA,QACA;AAAA,QACA;AAAA,QACA;AAAA,QACA;AAAA,QACA;AAAA,QACA;AAAA,QACA;AAAA,QACA;AAAA,QACA;AAAA,QACA;AAAA,QACA;AAAA,QACA;AAAA,QACA;AAAA,QACA;AAAA,QACA;AAAA,QACA;AAAA,QACA;AAAA,QACA;AAAA,QACA;AAAA,QACA;AAAA,QACA;AAAA,QACA;AAAA,QACA;AAAA,QACA;AAAA,QACA;AAAA,QACA;AAAA,QACA;AAAA,QACA;AAAA,QACA;AAAA,QACA;AAAA,QACA;AAAA,QACA;AAAA,QACA;AAAA,QACA;AAAA,MACF,EAAE,KAAK,IAAI;AAAA,MACX,MAAM,CAAC,UAAU;AAAA,IACnB;AAAA,IACA;AAAA,MACE,MAAM;AAAA,MACN,aACE;AAAA,MAC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,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA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AA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AA+IpB,IAAM,eAAe;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAwGrB,IAAM,cAAc;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AA2JpB,IAAM,eAAe;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAoIrB,IAAM,eAAe;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAmHrB,IAAM,cAAc;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAsHpB,IAAM,eAAe;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAuIrB,IAAM,eAAe;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAsHrB,IAAM,cAAc;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAwHpB,IAAM,cAAc;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAyHpB,IAAM,2BAA2B;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAqCjC,IAAM,+BAA+B;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAoIrC,IAAM,2BAA2B;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AA6TjC,IAAM,sCAGD;AAAA,EACH,EAAE,MAAM,yCAAyC,SAAS,YAAY;AAAA,EACtE,EAAE,MAAM,yCAAyC,SAAS,YAAY;AAAA,EACtE,EAAE,MAAM,0CAA0C,SAAS,aAAa;AAAA,EACxE,EAAE,MAAM,yCAAyC,SAAS,YAAY;AAAA,EACtE,EAAE,MAAM,0CAA0C,SAAS,aAAa;AAAA,EACxE,EAAE,MAAM,0CAA0C,SAAS,aAAa;AAAA,EACxE,EAAE,MAAM,yCAAyC,SAAS,YAAY;AAAA,EACtE,EAAE,MAAM,0CAA0C,SAAS,aAAa;AAAA,EACxE,EAAE,MAAM,0CAA0C,SAAS,aAAa;AAAA,EACxE,EAAE,MAAM,yCAAyC,SAAS,YAAY;AAAA,EACtE,EAAE,MAAM,yCAAyC,SAAS,YAAY;AAAA,EACtE;AAAA,IACE,MAAM;AAAA,IACN,SAAS;AAAA,EACX;AAAA,EACA;AAAA,IACE,MAAM;AAAA,IACN,SAAS;AAAA,EACX;AAAA,EACA;AAAA,IACE,MAAM;AAAA,IACN,SAAS;AAAA,EACX;AACF;AAgBA,IAAM,6BAA4C;AAAA,EAChD,MAAM;AAAA,EACN,aACE;AAAA,EACF,OAAO,YAAY;AAAA,EACnB,UAAU;AAAA,EACV,WAAW,EAAE,QAAQ,EAAE,SAAS,KAAK,EAAE;AAAA,EACvC,QAAQ;AAAA,IACN;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA,GAAG;AAAA,IACH;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,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AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;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IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,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","names":["Component","Component","Component","Component","Component","Component","Component","JsonFile","TextFile","TextFile","JsonFile","JsonFile","TextFile","GENERATED_MARKER","TextFile","JsonFile","path","Component","Component","TextFile","spec","import_utils","relative","Component","Component","relative","import_utils","Component","Component","Component","JsonFile","NodePackageManager","UpgradeDependenciesSchedule","merge","Component","Component","path","Component","JobPermission","JobPermission","Component","YamlFile","JobPermission","DEFAULT_WORKFLOW_NAME","NodePackageManager","UpgradeDependenciesSchedule","merge","NodePackageManager","Transform","UpgradeDependenciesSchedule","ReleaseTrigger","merge","import_utils","Component","GitHub","WorkflowSteps","JobPermission","Component","prefix","GitHub","JobPermission","WorkflowSteps","Component","GitHub","JobPermission","Component","GitHub","JobPermission","NodePackageManager","Transform","UpgradeDependenciesSchedule","ReleaseTrigger","merge","SampleFile","SampleFile","relative","Component"]}
|