@codedrifters/configulator 0.0.402 → 0.0.404
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 +110 -4
- package/lib/index.d.ts +111 -5
- package/lib/index.js +784 -622
- package/lib/index.js.map +1 -1
- package/lib/index.mjs +790 -632
- package/lib/index.mjs.map +1 -1
- package/package.json +1 -1
package/lib/index.js
CHANGED
|
@@ -222,6 +222,7 @@ __export(index_exports, {
|
|
|
222
222
|
DEFAULT_API_EXTRACTOR_REPORT_FILENAME: () => DEFAULT_API_EXTRACTOR_REPORT_FILENAME,
|
|
223
223
|
DEFAULT_API_EXTRACTOR_REPORT_FOLDER: () => DEFAULT_API_EXTRACTOR_REPORT_FOLDER,
|
|
224
224
|
DEFAULT_AUDIT_REPORT_DIR: () => DEFAULT_AUDIT_REPORT_DIR,
|
|
225
|
+
DEFAULT_BUILD_POLICY: () => DEFAULT_BUILD_POLICY,
|
|
225
226
|
DEFAULT_BUNDLE_OVERRIDES: () => DEFAULT_BUNDLE_OVERRIDES,
|
|
226
227
|
DEFAULT_DECOMPOSITION_TEMPLATE: () => DEFAULT_DECOMPOSITION_TEMPLATE,
|
|
227
228
|
DEFAULT_DISPATCH_MODEL: () => DEFAULT_DISPATCH_MODEL,
|
|
@@ -342,6 +343,7 @@ __export(index_exports, {
|
|
|
342
343
|
buildCompanyProfileBundle: () => buildCompanyProfileBundle,
|
|
343
344
|
buildCustomerProfileBundle: () => buildCustomerProfileBundle,
|
|
344
345
|
buildDocsSyncBundle: () => buildDocsSyncBundle,
|
|
346
|
+
buildGithubWorkflowBundle: () => buildGithubWorkflowBundle,
|
|
345
347
|
buildIndustryDiscoveryBundle: () => buildIndustryDiscoveryBundle,
|
|
346
348
|
buildMaintenanceAuditBundle: () => buildMaintenanceAuditBundle,
|
|
347
349
|
buildMeetingAnalysisBundle: () => buildMeetingAnalysisBundle,
|
|
@@ -356,6 +358,7 @@ __export(index_exports, {
|
|
|
356
358
|
buildResearchPipelineBundle: () => buildResearchPipelineBundle,
|
|
357
359
|
buildSoftwareProfileBundle: () => buildSoftwareProfileBundle,
|
|
358
360
|
buildStandardsResearchBundle: () => buildStandardsResearchBundle,
|
|
361
|
+
buildTurborepoBundle: () => buildTurborepoBundle,
|
|
359
362
|
buildUnblockDependentsProcedure: () => buildUnblockDependentsProcedure,
|
|
360
363
|
bundleNameForWorkflowRule: () => bundleNameForWorkflowRule,
|
|
361
364
|
businessModelsBundle: () => businessModelsBundle,
|
|
@@ -473,6 +476,7 @@ __export(index_exports, {
|
|
|
473
476
|
resolveAgentTiers: () => resolveAgentTiers,
|
|
474
477
|
resolveAstroProjectOutdir: () => resolveAstroProjectOutdir,
|
|
475
478
|
resolveAwsCdkProjectOutdir: () => resolveAwsCdkProjectOutdir,
|
|
479
|
+
resolveBuildPolicy: () => resolveBuildPolicy,
|
|
476
480
|
resolveBundleAgentTiers: () => resolveBundleAgentTiers,
|
|
477
481
|
resolveDefaultAgentTier: () => resolveDefaultAgentTier,
|
|
478
482
|
resolveIssueDefaults: () => resolveIssueDefaults,
|
|
@@ -4674,6 +4678,35 @@ function buildBaseBundle(paths = DEFAULT_AGENT_PATHS) {
|
|
|
4674
4678
|
"schema and consumer example. `status:deferred` is a valid",
|
|
4675
4679
|
"override value reserved for this exact use case.",
|
|
4676
4680
|
"",
|
|
4681
|
+
"### The `status:deferred` invariant",
|
|
4682
|
+
"",
|
|
4683
|
+
"**No agent, procedure, or sweep ever removes `status:deferred`.",
|
|
4684
|
+
"Only a human promotes a deferred issue.**",
|
|
4685
|
+
"",
|
|
4686
|
+
"`status:deferred` records a deliberate human decision to park",
|
|
4687
|
+
"work. Automation may read it, count it, and log it \u2014 but the",
|
|
4688
|
+
"label is cleared exclusively by a human (or by a scheduled task",
|
|
4689
|
+
"a human configured for that purpose). Concretely:",
|
|
4690
|
+
"",
|
|
4691
|
+
"- **Unblock sweeps skip it.** Both `check-blocked.sh unblock`",
|
|
4692
|
+
" and `unblock-dependents.sh` leave a `status:deferred` +",
|
|
4693
|
+
" `status:blocked` issue blocked when its dependencies close,",
|
|
4694
|
+
" emitting a `SKIP_DEFERRED #<n>` line instead of flipping to",
|
|
4695
|
+
" `status:ready`. Dependency resolution is not a promotion",
|
|
4696
|
+
" signal for parked work.",
|
|
4697
|
+
"- **Dispatch scans exclude it.** `check-blocked.sh eligible`",
|
|
4698
|
+
" drops any issue carrying `status:deferred`, so a stray",
|
|
4699
|
+
" `status:ready` + `status:deferred` pairing never reaches a",
|
|
4700
|
+
" worker.",
|
|
4701
|
+
"- **No sweep writes it either.** Automation adds",
|
|
4702
|
+
" `status:deferred` only at filing time via the configured",
|
|
4703
|
+
" `issueDefaults` \u2014 never as a runtime triage decision.",
|
|
4704
|
+
"",
|
|
4705
|
+
"An issue that legitimately needs to leave the parked backlog is",
|
|
4706
|
+
"promoted by a human removing `status:deferred` and setting the",
|
|
4707
|
+
"appropriate base status. Any automation that removes the label",
|
|
4708
|
+
"is a bug.",
|
|
4709
|
+
"",
|
|
4677
4710
|
"### Blocking Rules",
|
|
4678
4711
|
"",
|
|
4679
4712
|
"Two rules force `status:blocked` \u2014 both are non-negotiable:",
|
|
@@ -5875,6 +5908,403 @@ function buildBcmWriterBundle(paths = DEFAULT_AGENT_PATHS, issueDefaults = DEFAU
|
|
|
5875
5908
|
}
|
|
5876
5909
|
var bcmWriterBundle = buildBcmWriterBundle();
|
|
5877
5910
|
|
|
5911
|
+
// src/turbo/turbo-repo.ts
|
|
5912
|
+
var import_lib2 = require("projen/lib");
|
|
5913
|
+
var import_workflows_model = require("projen/lib/github/workflows-model");
|
|
5914
|
+
|
|
5915
|
+
// src/turbo/turbo-repo-task.ts
|
|
5916
|
+
var import_lib = require("projen/lib");
|
|
5917
|
+
var TurboRepoTask = class extends import_lib.Component {
|
|
5918
|
+
constructor(project, options) {
|
|
5919
|
+
super(project);
|
|
5920
|
+
this.project = project;
|
|
5921
|
+
this.name = options.name;
|
|
5922
|
+
this.dependsOn = options.dependsOn ?? [];
|
|
5923
|
+
this.env = options.env ?? [];
|
|
5924
|
+
this.passThroughEnv = options.passThroughEnv ?? [];
|
|
5925
|
+
this.outputs = options.outputs ?? [];
|
|
5926
|
+
this.cache = options.cache ?? true;
|
|
5927
|
+
this.inputs = [
|
|
5928
|
+
...options.inputs ?? [],
|
|
5929
|
+
// rerun if projen config changes
|
|
5930
|
+
".projen/**",
|
|
5931
|
+
// ignore mac files
|
|
5932
|
+
"!.DS_Store",
|
|
5933
|
+
"!**/.DS_Store"
|
|
5934
|
+
];
|
|
5935
|
+
this.outputLogs = options.outputLogs ?? "new-only";
|
|
5936
|
+
this.persistent = options.persistent ?? false;
|
|
5937
|
+
this.interactive = options.interactive ?? false;
|
|
5938
|
+
this.isActive = true;
|
|
5939
|
+
}
|
|
5940
|
+
taskConfig() {
|
|
5941
|
+
return {
|
|
5942
|
+
dependsOn: this.dependsOn,
|
|
5943
|
+
env: this.env,
|
|
5944
|
+
passThroughEnv: this.passThroughEnv,
|
|
5945
|
+
outputs: this.outputs,
|
|
5946
|
+
cache: this.cache,
|
|
5947
|
+
inputs: this.inputs,
|
|
5948
|
+
outputLogs: this.outputLogs,
|
|
5949
|
+
persistent: this.persistent,
|
|
5950
|
+
interactive: this.interactive
|
|
5951
|
+
};
|
|
5952
|
+
}
|
|
5953
|
+
};
|
|
5954
|
+
|
|
5955
|
+
// src/turbo/turbo-repo.ts
|
|
5956
|
+
var ROOT_TURBO_TASK_NAME = "turbo:build";
|
|
5957
|
+
var ROOT_CI_TASK_NAME = "build:all";
|
|
5958
|
+
var _TurboRepo = class _TurboRepo extends import_lib2.Component {
|
|
5959
|
+
constructor(project, options = {}) {
|
|
5960
|
+
super(project);
|
|
5961
|
+
this.project = project;
|
|
5962
|
+
/**
|
|
5963
|
+
* Sub-Tasks to run
|
|
5964
|
+
*/
|
|
5965
|
+
this.tasks = [];
|
|
5966
|
+
this.turboVersion = options.turboVersion ?? "catalog:";
|
|
5967
|
+
this.isRootProject = project === project.root;
|
|
5968
|
+
if (this.isRootProject) {
|
|
5969
|
+
project.addDevDeps(`turbo@${this.turboVersion}`);
|
|
5970
|
+
}
|
|
5971
|
+
project.gitignore.addPatterns("/.turbo");
|
|
5972
|
+
project.npmignore?.addPatterns("/.turbo/");
|
|
5973
|
+
this.extends = options.extends ?? (this.isRootProject ? [] : ["//"]);
|
|
5974
|
+
this.globalDependencies = options.globalDependencies ?? [];
|
|
5975
|
+
this.globalEnv = options.globalEnv ?? [];
|
|
5976
|
+
this.globalPassThroughEnv = options.globalPassThroughEnv ?? [];
|
|
5977
|
+
this.ui = options.ui ?? "stream";
|
|
5978
|
+
this.dangerouslyDisablePackageManagerCheck = options.dangerouslyDisablePackageManagerCheck ?? false;
|
|
5979
|
+
this.cacheDir = options.cacheDir ?? ".turbo/cache";
|
|
5980
|
+
this.daemon = options.daemon ?? true;
|
|
5981
|
+
this.envMode = options.envMode ?? "strict";
|
|
5982
|
+
this.runOptions = {
|
|
5983
|
+
...options.runOptions,
|
|
5984
|
+
summarize: options.runOptions?.summarize ?? true,
|
|
5985
|
+
concurrency: options.runOptions?.concurrency ?? 10
|
|
5986
|
+
};
|
|
5987
|
+
this.remoteCacheOptions = options.remoteCacheOptions;
|
|
5988
|
+
this.buildAllTaskEnvVars = options.buildAllTaskEnvVars ?? {};
|
|
5989
|
+
this.buildTask = new TurboRepoTask(this.project, {
|
|
5990
|
+
name: ROOT_TURBO_TASK_NAME,
|
|
5991
|
+
dependsOn: this.isRootProject ? [`^${ROOT_TURBO_TASK_NAME}`] : []
|
|
5992
|
+
});
|
|
5993
|
+
if (this.isRootProject) {
|
|
5994
|
+
this.buildAllTask = this.project.tasks.addTask(ROOT_CI_TASK_NAME, {
|
|
5995
|
+
description: "Root build followed by sub-project builds. Mimics the CI build process in one step."
|
|
5996
|
+
});
|
|
5997
|
+
this.buildAllTask.exec("turbo telemetry disable");
|
|
5998
|
+
if (this.buildAllTaskEnvVars) {
|
|
5999
|
+
Object.entries(this.buildAllTaskEnvVars).forEach(([name, value]) => {
|
|
6000
|
+
this.addGlobalEnvVar(name, value);
|
|
6001
|
+
});
|
|
6002
|
+
}
|
|
6003
|
+
if (!this.remoteCacheOptions) {
|
|
6004
|
+
this.buildAllTask.exec(
|
|
6005
|
+
`turbo ${ROOT_TURBO_TASK_NAME} ${this.renderRunArgs(false)}`
|
|
6006
|
+
);
|
|
6007
|
+
} else {
|
|
6008
|
+
this.buildAllTask.exec(
|
|
6009
|
+
`turbo ${ROOT_TURBO_TASK_NAME} ${this.renderRunArgs(true)}`,
|
|
6010
|
+
{
|
|
6011
|
+
condition: '[ ! -n "$CI" ]',
|
|
6012
|
+
env: {
|
|
6013
|
+
TURBO_ENDPOINT: `$(aws ssm get-parameter --name ${this.remoteCacheOptions.endpointParamName} --query Parameter.Value --output text --profile ${this.remoteCacheOptions.profileName})`,
|
|
6014
|
+
TURBO_TOKEN: `$(aws ssm get-parameter --name ${this.remoteCacheOptions.tokenParamName} --query Parameter.Value --output text --profile ${this.remoteCacheOptions.profileName})`
|
|
6015
|
+
}
|
|
6016
|
+
}
|
|
6017
|
+
);
|
|
6018
|
+
this.buildAllTask.exec(
|
|
6019
|
+
`turbo ${ROOT_TURBO_TASK_NAME} ${this.renderRunArgs(true)}`,
|
|
6020
|
+
{
|
|
6021
|
+
condition: '[ -n "$CI" ]',
|
|
6022
|
+
env: {
|
|
6023
|
+
TURBO_ENDPOINT: `$(aws ssm get-parameter --name ${this.remoteCacheOptions.endpointParamName} --query Parameter.Value --output text)`,
|
|
6024
|
+
TURBO_TOKEN: `$(aws ssm get-parameter --name ${this.remoteCacheOptions.tokenParamName} --query Parameter.Value --output text)`
|
|
6025
|
+
}
|
|
6026
|
+
}
|
|
6027
|
+
);
|
|
6028
|
+
}
|
|
6029
|
+
}
|
|
6030
|
+
if (!this.isRootProject) {
|
|
6031
|
+
this.preCompileTask = new TurboRepoTask(project, {
|
|
6032
|
+
name: options.preCompileTask?.name ?? "pre-compile",
|
|
6033
|
+
inputs: ["src/**"]
|
|
6034
|
+
});
|
|
6035
|
+
this.compileTask = new TurboRepoTask(project, {
|
|
6036
|
+
name: options.compileTask?.name ?? "compile",
|
|
6037
|
+
inputs: ["src/**"]
|
|
6038
|
+
});
|
|
6039
|
+
this.postCompileTask = new TurboRepoTask(project, {
|
|
6040
|
+
name: options.postCompileTask?.name ?? "post-compile",
|
|
6041
|
+
inputs: ["src/**"]
|
|
6042
|
+
});
|
|
6043
|
+
this.testTask = new TurboRepoTask(project, {
|
|
6044
|
+
name: options.testTask?.name ?? "test"
|
|
6045
|
+
});
|
|
6046
|
+
this.packageTask = new TurboRepoTask(project, {
|
|
6047
|
+
name: options.packageTask?.name ?? "package",
|
|
6048
|
+
inputs: [".npmignore"]
|
|
6049
|
+
});
|
|
6050
|
+
this.tasks.push(
|
|
6051
|
+
this.preCompileTask,
|
|
6052
|
+
this.compileTask,
|
|
6053
|
+
this.postCompileTask,
|
|
6054
|
+
this.testTask,
|
|
6055
|
+
this.packageTask
|
|
6056
|
+
);
|
|
6057
|
+
}
|
|
6058
|
+
}
|
|
6059
|
+
/**
|
|
6060
|
+
* Static method to discovert turbo in a project.
|
|
6061
|
+
*/
|
|
6062
|
+
static of(project) {
|
|
6063
|
+
const isDefined = (c) => c instanceof _TurboRepo;
|
|
6064
|
+
return project.components.find(isDefined);
|
|
6065
|
+
}
|
|
6066
|
+
/**
|
|
6067
|
+
* Render the `turbo run` CLI flag string for the `build:all` / `reset:all`
|
|
6068
|
+
* task commands from {@link runOptions}. With no `runOptions` configured the
|
|
6069
|
+
* output matches the historically hard-coded flags exactly.
|
|
6070
|
+
*
|
|
6071
|
+
* @param remote - when `true`, also emit the remote-cache flags
|
|
6072
|
+
* (`--cache=remote:rw` plus `--api` / `--token` / `--team` derived from
|
|
6073
|
+
* {@link remoteCacheOptions}). The remote-cache `build:all` variant passes
|
|
6074
|
+
* `true`; `reset:all` and the local `build:all` variant pass `false`.
|
|
6075
|
+
*/
|
|
6076
|
+
renderRunArgs(remote) {
|
|
6077
|
+
const run = this.runOptions;
|
|
6078
|
+
const args = [];
|
|
6079
|
+
if (run.summarize) {
|
|
6080
|
+
args.push("--summarize");
|
|
6081
|
+
}
|
|
6082
|
+
args.push(`--concurrency=${run.concurrency}`);
|
|
6083
|
+
if (run.force) {
|
|
6084
|
+
args.push("--force");
|
|
6085
|
+
}
|
|
6086
|
+
if (run.noCache) {
|
|
6087
|
+
args.push("--no-cache");
|
|
6088
|
+
}
|
|
6089
|
+
if (run.only) {
|
|
6090
|
+
args.push("--only");
|
|
6091
|
+
}
|
|
6092
|
+
if (run.affected) {
|
|
6093
|
+
args.push("--affected");
|
|
6094
|
+
}
|
|
6095
|
+
if (run.cacheWorkers !== void 0) {
|
|
6096
|
+
args.push(`--cache-workers=${run.cacheWorkers}`);
|
|
6097
|
+
}
|
|
6098
|
+
if (run.continueOn !== void 0) {
|
|
6099
|
+
args.push(`--continue=${run.continueOn}`);
|
|
6100
|
+
}
|
|
6101
|
+
if (run.frameworkInference !== void 0) {
|
|
6102
|
+
args.push(`--framework-inference=${run.frameworkInference}`);
|
|
6103
|
+
}
|
|
6104
|
+
for (const filter of run.filter ?? []) {
|
|
6105
|
+
args.push(`--filter=${filter}`);
|
|
6106
|
+
}
|
|
6107
|
+
if (run.outputLogs !== void 0) {
|
|
6108
|
+
args.push(`--output-logs=${run.outputLogs}`);
|
|
6109
|
+
}
|
|
6110
|
+
if (run.logOrder !== void 0) {
|
|
6111
|
+
args.push(`--log-order=${run.logOrder}`);
|
|
6112
|
+
}
|
|
6113
|
+
if (run.logPrefix !== void 0) {
|
|
6114
|
+
args.push(`--log-prefix=${run.logPrefix}`);
|
|
6115
|
+
}
|
|
6116
|
+
if (run.dryRun !== void 0) {
|
|
6117
|
+
args.push(`--dry-run=${run.dryRun}`);
|
|
6118
|
+
}
|
|
6119
|
+
const cache = run.cache ?? (remote ? "remote:rw" : void 0);
|
|
6120
|
+
if (cache !== void 0) {
|
|
6121
|
+
args.push(`--cache=${cache}`);
|
|
6122
|
+
}
|
|
6123
|
+
if (remote && this.remoteCacheOptions) {
|
|
6124
|
+
args.push(
|
|
6125
|
+
"--api=$TURBO_ENDPOINT",
|
|
6126
|
+
"--token=$TURBO_TOKEN",
|
|
6127
|
+
`--team=${this.remoteCacheOptions.teamName}`
|
|
6128
|
+
);
|
|
6129
|
+
}
|
|
6130
|
+
if (run.additionalArgs) {
|
|
6131
|
+
args.push(...run.additionalArgs);
|
|
6132
|
+
}
|
|
6133
|
+
return args.join(" ");
|
|
6134
|
+
}
|
|
6135
|
+
/**
|
|
6136
|
+
* Add an env var to the global env vars for all tasks.
|
|
6137
|
+
* This will also become an input for the build:all task cache at the root.
|
|
6138
|
+
*/
|
|
6139
|
+
addGlobalEnvVar(name, value) {
|
|
6140
|
+
this.buildAllTask?.env(name, value);
|
|
6141
|
+
if (this.isRootProject) {
|
|
6142
|
+
this.globalEnv.push(name);
|
|
6143
|
+
}
|
|
6144
|
+
}
|
|
6145
|
+
activateBranchNameEnvVar(options) {
|
|
6146
|
+
const value = '$([ -n "$GIT_BRANCH_NAME" ] && echo "$GIT_BRANCH_NAME" || git rev-parse --abbrev-ref HEAD)';
|
|
6147
|
+
if (options === void 0) {
|
|
6148
|
+
this.project.logger.warn(
|
|
6149
|
+
"TurboRepo.activateBranchNameEnvVar() with no arguments is deprecated. It writes GIT_BRANCH_NAME to the root `globalEnv`, which forces every task in the monorepo to miss cache on every branch switch. Pass `{ tasks: [...] }` and name only the tasks that actually consume the branch (e.g. CDK synth/package) to preserve cross-branch cache hits for everything else."
|
|
6150
|
+
);
|
|
6151
|
+
this.addGlobalEnvVar("GIT_BRANCH_NAME", value);
|
|
6152
|
+
return;
|
|
6153
|
+
}
|
|
6154
|
+
const knownTaskNames = this.tasks.map((task) => task.name);
|
|
6155
|
+
const unknown = options.tasks.filter(
|
|
6156
|
+
(name) => !knownTaskNames.includes(name)
|
|
6157
|
+
);
|
|
6158
|
+
if (unknown.length > 0) {
|
|
6159
|
+
throw new Error(
|
|
6160
|
+
`TurboRepo.activateBranchNameEnvVar: unknown task name(s) ${JSON.stringify(
|
|
6161
|
+
unknown
|
|
6162
|
+
)}. Known tasks on this TurboRepo: ${JSON.stringify(knownTaskNames)}.`
|
|
6163
|
+
);
|
|
6164
|
+
}
|
|
6165
|
+
for (const name of options.tasks) {
|
|
6166
|
+
const task = this.tasks.find((t) => t.name === name);
|
|
6167
|
+
if (task && !task.env.includes("GIT_BRANCH_NAME")) {
|
|
6168
|
+
task.env.push("GIT_BRANCH_NAME");
|
|
6169
|
+
}
|
|
6170
|
+
}
|
|
6171
|
+
}
|
|
6172
|
+
/**
|
|
6173
|
+
* Paths of all generated files in the project, deduped, for use as task
|
|
6174
|
+
* inputs so the compile cache invalidates when they change. Includes
|
|
6175
|
+
* projen-managed `FileBase` files plus generated-once `SampleFile` /
|
|
6176
|
+
* `SampleDir` — whose paths projen keeps private, so they are read defensively
|
|
6177
|
+
* and skipped if that internal shape ever changes. Computed at synth time so
|
|
6178
|
+
* files added after this component (e.g. a subclass's SampleFiles) are seen.
|
|
6179
|
+
*/
|
|
6180
|
+
generatedFileInputs() {
|
|
6181
|
+
const inputs = /* @__PURE__ */ new Set();
|
|
6182
|
+
for (const component of this.project.components) {
|
|
6183
|
+
if (component instanceof import_lib2.FileBase) {
|
|
6184
|
+
inputs.add(component.path);
|
|
6185
|
+
} else if (component instanceof import_lib2.SampleFile) {
|
|
6186
|
+
const filePath = component.filePath;
|
|
6187
|
+
if (typeof filePath === "string") {
|
|
6188
|
+
inputs.add(filePath);
|
|
6189
|
+
}
|
|
6190
|
+
} else if (component instanceof import_lib2.SampleDir) {
|
|
6191
|
+
const dir = component.dir;
|
|
6192
|
+
if (typeof dir === "string") {
|
|
6193
|
+
inputs.add(`${dir}/**`);
|
|
6194
|
+
}
|
|
6195
|
+
}
|
|
6196
|
+
}
|
|
6197
|
+
return Array.from(inputs);
|
|
6198
|
+
}
|
|
6199
|
+
preSynthesize() {
|
|
6200
|
+
let nextDependsOn = this.project.deps.all.filter((d) => d.version === "workspace:*").map((d) => [d.name, ROOT_TURBO_TASK_NAME].join("#"));
|
|
6201
|
+
if (!this.isRootProject) {
|
|
6202
|
+
[
|
|
6203
|
+
[this.project.preCompileTask, this.preCompileTask],
|
|
6204
|
+
[this.project.compileTask, this.compileTask],
|
|
6205
|
+
[this.project.postCompileTask, this.postCompileTask],
|
|
6206
|
+
[this.project.testTask, this.testTask],
|
|
6207
|
+
[this.project.packageTask, this.packageTask]
|
|
6208
|
+
].forEach(([pjTask, turboTask]) => {
|
|
6209
|
+
if (pjTask && turboTask && pjTask.steps.length > 0) {
|
|
6210
|
+
if (nextDependsOn.length > 0) {
|
|
6211
|
+
turboTask.dependsOn.push(...nextDependsOn);
|
|
6212
|
+
}
|
|
6213
|
+
nextDependsOn = [turboTask.name];
|
|
6214
|
+
} else {
|
|
6215
|
+
turboTask.isActive = false;
|
|
6216
|
+
}
|
|
6217
|
+
});
|
|
6218
|
+
this.buildTask.dependsOn.push(...nextDependsOn);
|
|
6219
|
+
}
|
|
6220
|
+
const generatedInputs = this.generatedFileInputs();
|
|
6221
|
+
const appendGeneratedInputs = (task) => {
|
|
6222
|
+
if (!task) {
|
|
6223
|
+
return;
|
|
6224
|
+
}
|
|
6225
|
+
for (const input of generatedInputs) {
|
|
6226
|
+
if (!task.inputs.includes(input)) {
|
|
6227
|
+
task.inputs.push(input);
|
|
6228
|
+
}
|
|
6229
|
+
}
|
|
6230
|
+
};
|
|
6231
|
+
if (this.isRootProject) {
|
|
6232
|
+
appendGeneratedInputs(this.buildTask);
|
|
6233
|
+
} else {
|
|
6234
|
+
appendGeneratedInputs(this.preCompileTask);
|
|
6235
|
+
appendGeneratedInputs(this.compileTask);
|
|
6236
|
+
appendGeneratedInputs(this.postCompileTask);
|
|
6237
|
+
}
|
|
6238
|
+
const fileName = "turbo.json";
|
|
6239
|
+
this.project.addPackageIgnore(fileName);
|
|
6240
|
+
new import_lib2.JsonFile(this.project, fileName, {
|
|
6241
|
+
obj: {
|
|
6242
|
+
extends: this.extends.length ? this.extends : void 0,
|
|
6243
|
+
globalDependencies: this.isRootProject && this.globalDependencies.length ? this.globalDependencies : void 0,
|
|
6244
|
+
globalEnv: this.isRootProject && this.globalEnv.length ? this.globalEnv : void 0,
|
|
6245
|
+
globalPassThroughEnv: this.isRootProject && this.globalPassThroughEnv.length ? this.globalPassThroughEnv : void 0,
|
|
6246
|
+
ui: this.isRootProject ? this.ui : void 0,
|
|
6247
|
+
dangerouslyDisablePackageManagerCheck: this.isRootProject ? this.dangerouslyDisablePackageManagerCheck : void 0,
|
|
6248
|
+
cacheDir: this.isRootProject ? this.cacheDir : void 0,
|
|
6249
|
+
envMode: this.isRootProject ? this.envMode : void 0,
|
|
6250
|
+
/**
|
|
6251
|
+
* All tasks
|
|
6252
|
+
*/
|
|
6253
|
+
tasks: this.tasks.filter((task) => task.isActive).reduce(
|
|
6254
|
+
(acc, task) => {
|
|
6255
|
+
acc[task.name] = {
|
|
6256
|
+
...task.taskConfig()
|
|
6257
|
+
};
|
|
6258
|
+
return acc;
|
|
6259
|
+
},
|
|
6260
|
+
{
|
|
6261
|
+
[this.buildTask.name]: { ...this.buildTask.taskConfig() }
|
|
6262
|
+
}
|
|
6263
|
+
)
|
|
6264
|
+
}
|
|
6265
|
+
});
|
|
6266
|
+
super.preSynthesize();
|
|
6267
|
+
}
|
|
6268
|
+
};
|
|
6269
|
+
_TurboRepo.buildWorkflowOptions = (remoteCacheOptions) => {
|
|
6270
|
+
return {
|
|
6271
|
+
env: {
|
|
6272
|
+
GIT_BRANCH_NAME: "${{ github.head_ref || github.ref_name }}"
|
|
6273
|
+
},
|
|
6274
|
+
permissions: {
|
|
6275
|
+
contents: import_workflows_model.JobPermission.WRITE,
|
|
6276
|
+
idToken: import_workflows_model.JobPermission.WRITE
|
|
6277
|
+
},
|
|
6278
|
+
preBuildSteps: [
|
|
6279
|
+
{
|
|
6280
|
+
name: "AWS Creds for SSM",
|
|
6281
|
+
uses: "aws-actions/configure-aws-credentials@v6",
|
|
6282
|
+
with: {
|
|
6283
|
+
["role-to-assume"]: remoteCacheOptions.oidcRole,
|
|
6284
|
+
["aws-region"]: "us-east-1",
|
|
6285
|
+
["role-duration-seconds"]: "900"
|
|
6286
|
+
}
|
|
6287
|
+
}
|
|
6288
|
+
]
|
|
6289
|
+
};
|
|
6290
|
+
};
|
|
6291
|
+
var TurboRepo = _TurboRepo;
|
|
6292
|
+
|
|
6293
|
+
// src/agent/bundles/build-policy.ts
|
|
6294
|
+
var DEFAULT_BUILD_POLICY = {
|
|
6295
|
+
remoteCacheEnabled: false
|
|
6296
|
+
};
|
|
6297
|
+
function resolveBuildPolicy(project) {
|
|
6298
|
+
const remoteCacheOptions = TurboRepo.of(project)?.remoteCacheOptions;
|
|
6299
|
+
if (!remoteCacheOptions) {
|
|
6300
|
+
return DEFAULT_BUILD_POLICY;
|
|
6301
|
+
}
|
|
6302
|
+
return {
|
|
6303
|
+
remoteCacheEnabled: true,
|
|
6304
|
+
awsProfileName: remoteCacheOptions.profileName
|
|
6305
|
+
};
|
|
6306
|
+
}
|
|
6307
|
+
|
|
5878
6308
|
// src/agent/bundles/business-models.ts
|
|
5879
6309
|
var TEMPLATE_CANVAS = `---
|
|
5880
6310
|
title: "Business Model: <Segment Name>"
|
|
@@ -10813,188 +11243,210 @@ var cleanMergedBranchesSkill = {
|
|
|
10813
11243
|
}
|
|
10814
11244
|
]
|
|
10815
11245
|
};
|
|
10816
|
-
|
|
10817
|
-
|
|
10818
|
-
|
|
10819
|
-
|
|
10820
|
-
|
|
10821
|
-
|
|
10822
|
-
|
|
10823
|
-
|
|
10824
|
-
|
|
10825
|
-
|
|
10826
|
-
|
|
10827
|
-
|
|
10828
|
-
|
|
10829
|
-
|
|
10830
|
-
|
|
10831
|
-
|
|
10832
|
-
|
|
10833
|
-
|
|
10834
|
-
|
|
10835
|
-
|
|
10836
|
-
|
|
10837
|
-
|
|
10838
|
-
|
|
10839
|
-
|
|
10840
|
-
|
|
10841
|
-
|
|
10842
|
-
|
|
10843
|
-
"
|
|
10844
|
-
|
|
10845
|
-
|
|
10846
|
-
|
|
10847
|
-
|
|
10848
|
-
|
|
10849
|
-
|
|
10850
|
-
|
|
10851
|
-
"
|
|
10852
|
-
|
|
10853
|
-
|
|
10854
|
-
|
|
10855
|
-
"
|
|
10856
|
-
"
|
|
10857
|
-
|
|
10858
|
-
|
|
10859
|
-
|
|
10860
|
-
|
|
10861
|
-
|
|
10862
|
-
|
|
10863
|
-
|
|
10864
|
-
|
|
10865
|
-
|
|
10866
|
-
|
|
10867
|
-
|
|
10868
|
-
|
|
10869
|
-
|
|
10870
|
-
|
|
10871
|
-
|
|
10872
|
-
|
|
10873
|
-
|
|
10874
|
-
|
|
10875
|
-
|
|
10876
|
-
|
|
10877
|
-
|
|
10878
|
-
|
|
10879
|
-
|
|
10880
|
-
|
|
10881
|
-
|
|
10882
|
-
|
|
10883
|
-
|
|
10884
|
-
|
|
10885
|
-
|
|
10886
|
-
|
|
10887
|
-
|
|
10888
|
-
|
|
10889
|
-
|
|
10890
|
-
|
|
10891
|
-
|
|
10892
|
-
|
|
10893
|
-
|
|
10894
|
-
|
|
10895
|
-
|
|
10896
|
-
|
|
10897
|
-
|
|
10898
|
-
|
|
10899
|
-
|
|
10900
|
-
|
|
10901
|
-
|
|
10902
|
-
|
|
10903
|
-
|
|
10904
|
-
|
|
10905
|
-
|
|
10906
|
-
|
|
10907
|
-
|
|
10908
|
-
|
|
10909
|
-
|
|
10910
|
-
|
|
10911
|
-
|
|
10912
|
-
|
|
10913
|
-
|
|
10914
|
-
|
|
10915
|
-
|
|
10916
|
-
|
|
10917
|
-
|
|
10918
|
-
|
|
10919
|
-
|
|
10920
|
-
|
|
10921
|
-
|
|
10922
|
-
|
|
10923
|
-
|
|
10924
|
-
|
|
10925
|
-
|
|
10926
|
-
|
|
10927
|
-
|
|
10928
|
-
|
|
10929
|
-
|
|
10930
|
-
|
|
10931
|
-
|
|
10932
|
-
|
|
10933
|
-
|
|
10934
|
-
|
|
10935
|
-
|
|
10936
|
-
|
|
10937
|
-
|
|
10938
|
-
|
|
10939
|
-
|
|
10940
|
-
|
|
10941
|
-
|
|
10942
|
-
|
|
10943
|
-
|
|
10944
|
-
|
|
10945
|
-
|
|
10946
|
-
"",
|
|
10947
|
-
|
|
10948
|
-
|
|
10949
|
-
|
|
10950
|
-
|
|
10951
|
-
|
|
10952
|
-
|
|
10953
|
-
|
|
10954
|
-
|
|
10955
|
-
|
|
10956
|
-
|
|
10957
|
-
|
|
10958
|
-
|
|
10959
|
-
|
|
10960
|
-
|
|
10961
|
-
|
|
10962
|
-
|
|
10963
|
-
|
|
10964
|
-
|
|
10965
|
-
|
|
10966
|
-
|
|
10967
|
-
|
|
10968
|
-
|
|
10969
|
-
|
|
10970
|
-
|
|
10971
|
-
|
|
10972
|
-
|
|
10973
|
-
|
|
10974
|
-
|
|
10975
|
-
|
|
10976
|
-
|
|
10977
|
-
|
|
10978
|
-
|
|
10979
|
-
|
|
10980
|
-
|
|
10981
|
-
|
|
10982
|
-
|
|
10983
|
-
|
|
10984
|
-
|
|
10985
|
-
|
|
10986
|
-
|
|
10987
|
-
|
|
10988
|
-
|
|
10989
|
-
"
|
|
10990
|
-
"
|
|
10991
|
-
|
|
10992
|
-
|
|
10993
|
-
|
|
10994
|
-
|
|
10995
|
-
|
|
10996
|
-
|
|
10997
|
-
|
|
11246
|
+
function renderPrWorkflowBuildStep(policy) {
|
|
11247
|
+
const lines = [
|
|
11248
|
+
"2. **Run the build \u2014 scoped to what changed.**",
|
|
11249
|
+
"",
|
|
11250
|
+
" - **Documentation-only changes** \u2014 a diff confined to documentation content (markdown pages, no source, config, or projen inputs) does **not** require `pnpm build:all`. There is nothing to compile, and CI is the authoritative content gate. Commit the content and proceed to the next step.",
|
|
11251
|
+
" - **Everything else** \u2014 when the change touches build inputs (source code, `.projenrc.ts`, `projenrc/**`, or any other projen-generated config), run `pnpm build:all` to compile, lint, and test all packages (mirrors the CI pipeline). If the build produces changes to turbo inputs (typically snapshot files or ESLint auto-fixes), commit those changes and run `pnpm build:all` again \u2014 the build must complete cleanly with no uncommitted changes."
|
|
11252
|
+
];
|
|
11253
|
+
if (policy.remoteCacheEnabled && policy.awsProfileName) {
|
|
11254
|
+
lines.push(
|
|
11255
|
+
"",
|
|
11256
|
+
` \`pnpm build:all\` uses the Turborepo **remote cache**, which requires the user to be authenticated to AWS on the \`${policy.awsProfileName}\` profile. If the command fails due to AWS credentials, ask the user to authenticate first.`
|
|
11257
|
+
);
|
|
11258
|
+
}
|
|
11259
|
+
lines.push(
|
|
11260
|
+
"",
|
|
11261
|
+
" **Never background a long build and end the turn.** If you run a build, run it in the **foreground** to completion before committing, pushing, or opening the PR. Launching `pnpm build:all` as a background process and ending your turn while it is still running strands the deliverable uncommitted \u2014 that work is lost. This is the documented root cause of autonomous worker-stall incidents."
|
|
11262
|
+
);
|
|
11263
|
+
return lines;
|
|
11264
|
+
}
|
|
11265
|
+
function buildGithubWorkflowBundle(buildPolicy = DEFAULT_BUILD_POLICY) {
|
|
11266
|
+
return {
|
|
11267
|
+
name: "github-workflow",
|
|
11268
|
+
description: "GitHub issue and PR workflow automation patterns",
|
|
11269
|
+
appliesWhen: (project) => hasComponent(project, import_github.GitHub),
|
|
11270
|
+
rules: [
|
|
11271
|
+
{
|
|
11272
|
+
name: "issue-workflow",
|
|
11273
|
+
description: "Automated workflow for starting work on a GitHub issue",
|
|
11274
|
+
scope: AGENT_RULE_SCOPE.ALWAYS,
|
|
11275
|
+
content: [
|
|
11276
|
+
"# Issue Workflow",
|
|
11277
|
+
"",
|
|
11278
|
+
'## "Work on issue X" Automation',
|
|
11279
|
+
"",
|
|
11280
|
+
"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 \u2014 the agent handles the full workflow (claim, branch, plan, implement, PR) and will pause for your approval at the appropriate checkpoints."
|
|
11281
|
+
].join("\n"),
|
|
11282
|
+
tags: ["workflow"]
|
|
11283
|
+
},
|
|
11284
|
+
{
|
|
11285
|
+
name: "create-issue-workflow",
|
|
11286
|
+
description: "Automated workflow for creating a new GitHub issue",
|
|
11287
|
+
// ALWAYS scope: users invoke "create an issue" from any
|
|
11288
|
+
// context, not only when editing agent / skill / bundle source.
|
|
11289
|
+
// Consumers that want to narrow the load can override via
|
|
11290
|
+
// `agentConfig.additionalRulePaths` or `excludeRules`.
|
|
11291
|
+
scope: AGENT_RULE_SCOPE.ALWAYS,
|
|
11292
|
+
content: [
|
|
11293
|
+
"# Create Issue Workflow",
|
|
11294
|
+
"",
|
|
11295
|
+
'## "Create an issue" Automation',
|
|
11296
|
+
"",
|
|
11297
|
+
"When the user says **create an issue** (or similar), follow these steps exactly:",
|
|
11298
|
+
"",
|
|
11299
|
+
"1. **Determine the issue type prefix** from the user's description:",
|
|
11300
|
+
" - `epic:` \u2014 Large initiatives spanning multiple child issues",
|
|
11301
|
+
" - `feat:` \u2014 New features or functionality",
|
|
11302
|
+
" - `fix:` \u2014 Bug fixes",
|
|
11303
|
+
" - `chore:` \u2014 Maintenance: deps, tooling, config",
|
|
11304
|
+
" - `docs:` \u2014 Documentation-only work",
|
|
11305
|
+
" - `refactor:` \u2014 Code restructure, no behavior change",
|
|
11306
|
+
" - `release:` \u2014 Release preparation, version bumps",
|
|
11307
|
+
" - `hotfix:` \u2014 Urgent production fixes",
|
|
11308
|
+
" - If unclear, ask the user which type applies",
|
|
11309
|
+
"2. **Compose the issue title** in the format: `<type>: <short description>`",
|
|
11310
|
+
"3. **Determine the GitHub issue type** based on the prefix:",
|
|
11311
|
+
" - `epic:` \u2192 Epic",
|
|
11312
|
+
" - `feat:` \u2192 Feature",
|
|
11313
|
+
" - `fix:` \u2192 Bug",
|
|
11314
|
+
" - `chore:`, `docs:`, `refactor:`, `release:`, `hotfix:` \u2192 Task",
|
|
11315
|
+
"4. **Identify prerequisite issues** \u2014 if the user mentions dependencies or blockers, include a **Dependencies** section in the body with `Depends on: #<issue-number>`",
|
|
11316
|
+
"5. **Determine labels** \u2014 every issue must be created with the following labels:",
|
|
11317
|
+
" - **`type:*`** \u2014 derived from the issue title prefix:",
|
|
11318
|
+
" - `epic:` \u2192 `type:feat`",
|
|
11319
|
+
" - `feat:` \u2192 `type:feat`",
|
|
11320
|
+
" - `fix:` \u2192 `type:fix`",
|
|
11321
|
+
" - `chore:` \u2192 `type:chore`",
|
|
11322
|
+
" - `docs:` \u2192 `type:docs`",
|
|
11323
|
+
" - `refactor:` \u2192 `type:refactor`",
|
|
11324
|
+
" - `release:` \u2192 `type:release`",
|
|
11325
|
+
" - `hotfix:` \u2192 `type:hotfix`",
|
|
11326
|
+
' - **`priority:*`** \u2014 infer from the user\'s description when possible (e.g., "urgent"/"critical" \u2192 `priority:critical`, "important" \u2192 `priority:high`, "minor"/"low priority" \u2192 `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`',
|
|
11327
|
+
" - **`status:ready`** \u2014 always add unless the issue has dependencies or blockers, in which case use `status:blocked`",
|
|
11328
|
+
"6. **Create the issue** using `gh issue create`:",
|
|
11329
|
+
" - `--title '<type>: <description>'`",
|
|
11330
|
+
" - `--body '<issue body>'`",
|
|
11331
|
+
" - `--label '<type-label>' --label '<priority-label>' --label '<status-label>'`",
|
|
11332
|
+
"7. **Set the GitHub issue type** by invoking the `set-issue-type.sh` helper (shipped with this bundle):",
|
|
11333
|
+
"",
|
|
11334
|
+
" ```sh",
|
|
11335
|
+
" .claude/procedures/set-issue-type.sh <issue-number> <Feature|Task|Epic|Bug>",
|
|
11336
|
+
" ```",
|
|
11337
|
+
"",
|
|
11338
|
+
" The helper resolves owner/repo, looks up the issue type node ID, looks up the issue node ID, and applies the `updateIssueIssueType` mutation in one step. It exits non-zero with a clear diagnostic on any error and lists available types if the type name is not recognised.",
|
|
11339
|
+
"",
|
|
11340
|
+
" **Under the hood** (documented fallback if the helper is unavailable): the helper performs a two-step GraphQL flow \u2014 first a `repository(...).issueTypes` query to map the human-readable type name to a node ID, then the `updateIssueIssueType` mutation. The canonical queries are:",
|
|
11341
|
+
"",
|
|
11342
|
+
" ```sh",
|
|
11343
|
+
" gh api graphql -f query='query($owner:String!,$repo:String!){repository(owner:$owner,name:$repo){issueTypes(first:50){nodes{id name}}}}' -f owner=<owner> -f repo=<repo>",
|
|
11344
|
+
" 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>",
|
|
11345
|
+
" ```",
|
|
11346
|
+
"",
|
|
11347
|
+
"### Issue Body Template",
|
|
11348
|
+
"",
|
|
11349
|
+
"```markdown",
|
|
11350
|
+
"## Summary",
|
|
11351
|
+
"",
|
|
11352
|
+
"<1-3 sentences describing the issue>",
|
|
11353
|
+
"",
|
|
11354
|
+
"## Details",
|
|
11355
|
+
"",
|
|
11356
|
+
"<Detailed description, acceptance criteria, or reproduction steps as appropriate>",
|
|
11357
|
+
"",
|
|
11358
|
+
"## Dependencies",
|
|
11359
|
+
"",
|
|
11360
|
+
"Depends on: #<issue-number> (if any, otherwise omit this section)",
|
|
11361
|
+
"```",
|
|
11362
|
+
"",
|
|
11363
|
+
"### Important",
|
|
11364
|
+
"",
|
|
11365
|
+
"- Always use the conventional prefix in the issue title",
|
|
11366
|
+
"- Always assign the correct GitHub issue type via the `set-issue-type.sh` helper (step 7) \u2014 never via `gh issue create --type`",
|
|
11367
|
+
"- Always include `type:*`, `priority:*`, and `status:*` labels",
|
|
11368
|
+
"- If the user does not specify a type, ask before creating the issue",
|
|
11369
|
+
"- If the priority cannot be inferred from the description, ask the user before creating the issue",
|
|
11370
|
+
"- Keep titles concise and descriptive"
|
|
11371
|
+
].join("\n"),
|
|
11372
|
+
tags: ["workflow"]
|
|
11373
|
+
},
|
|
11374
|
+
{
|
|
11375
|
+
name: "pr-workflow",
|
|
11376
|
+
description: "Automated workflow for opening a pull request",
|
|
11377
|
+
scope: AGENT_RULE_SCOPE.ALWAYS,
|
|
11378
|
+
content: [
|
|
11379
|
+
"# PR Workflow",
|
|
11380
|
+
"",
|
|
11381
|
+
'## "Open a PR" Automation',
|
|
11382
|
+
"",
|
|
11383
|
+
"When the user says **open a PR** (or similar), follow these steps exactly:",
|
|
11384
|
+
"",
|
|
11385
|
+
"1. **Regenerate project files** \u2014 run the three-step regen sequence (`pnpm i`, then `pnpm exec projen`, then `pnpm i` again) to ensure all generated files are up to date. The leading `pnpm i` is required because `pnpm exec projen` synthesises against whatever version of configulator (and projen, and any projen plugins) is currently resolved in `node_modules`; if the lockfile has moved past `node_modules` (typically right after `git pull` lands a dependency upgrade, or on a fresh checkout), synth runs against stale templates and produces phantom drift in `.claude/`, `.github/labels.yml`, `CLAUDE.md`, and other generated files. The trailing `pnpm i` picks up any dependency changes projen wrote into `package.json` during synth. Check `git diff` after the third step \u2014 if there are changes, commit them before proceeding.",
|
|
11386
|
+
...renderPrWorkflowBuildStep(buildPolicy),
|
|
11387
|
+
"3. **Check for uncommitted changes** \u2014 if any exist, commit them with a conventional commit message",
|
|
11388
|
+
"4. **Pull and rebase from the default branch** \u2014 run `git pull origin {{repository.defaultBranch}} --rebase` to incorporate the latest changes and resolve any conflicts before pushing",
|
|
11389
|
+
"5. **Push the branch** to origin: `git push -u origin <branch>`",
|
|
11390
|
+
"6. **Create the PR** using `gh pr create`:",
|
|
11391
|
+
" - **Title**: use a conventional commit style title (e.g., `feat(scope): short description`)",
|
|
11392
|
+
" - **Body**: include `Closes #<issue-number>` (derived from the branch name) and a brief summary of changes",
|
|
11393
|
+
"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 \u2014 review/merge policy lives solely in the `pr-reviewer` agent.",
|
|
11394
|
+
"",
|
|
11395
|
+
"### PR Body Template",
|
|
11396
|
+
"",
|
|
11397
|
+
"```markdown",
|
|
11398
|
+
"## Summary",
|
|
11399
|
+
"",
|
|
11400
|
+
"<1-3 bullet points describing what changed and why>",
|
|
11401
|
+
"",
|
|
11402
|
+
"Closes #<issue-number>",
|
|
11403
|
+
"",
|
|
11404
|
+
"## Test Plan",
|
|
11405
|
+
"",
|
|
11406
|
+
"- [ ] Tests pass locally",
|
|
11407
|
+
"- [ ] Relevant changes have been reviewed",
|
|
11408
|
+
"```",
|
|
11409
|
+
"",
|
|
11410
|
+
"### Important",
|
|
11411
|
+
"",
|
|
11412
|
+
"- Always derive the issue number from the branch name (e.g., `feat/42-add-login` \u2192 `#42`)",
|
|
11413
|
+
"- Use conventional commit format for the PR title",
|
|
11414
|
+
"- Delegate merge to the `pr-reviewer` sub-agent \u2014 do not merge manually and do not enable auto-merge directly"
|
|
11415
|
+
].join("\n"),
|
|
11416
|
+
tags: ["workflow"]
|
|
11417
|
+
},
|
|
11418
|
+
{
|
|
11419
|
+
name: "branch-cleanup",
|
|
11420
|
+
description: "Local-branch hygiene helpers shipped with the github-workflow bundle, including the /clean-merged-branches skill for safely force-deleting branches whose content has already merged into the base (handles squash merges).",
|
|
11421
|
+
scope: AGENT_RULE_SCOPE.ALWAYS,
|
|
11422
|
+
content: [
|
|
11423
|
+
"# Branch Cleanup",
|
|
11424
|
+
"",
|
|
11425
|
+
"Local branches accumulate after every merged PR. In squash-merge",
|
|
11426
|
+
"repositories `git branch -d` refuses to delete them because the",
|
|
11427
|
+
"commit hash on the base differs, even when the branch content is",
|
|
11428
|
+
"fully merged. The `github-workflow` bundle ships two affordances",
|
|
11429
|
+
"that use content-equality (not commit-graph reachability) to",
|
|
11430
|
+
"identify branches safe to force-delete:",
|
|
11431
|
+
"",
|
|
11432
|
+
"- `/clean-merged-branches` \u2014 interactive slash-command skill that",
|
|
11433
|
+
" classifies every local branch, prompts for confirmation, then",
|
|
11434
|
+
" runs `git branch -D` on the confirmed list. See",
|
|
11435
|
+
" `.claude/skills/clean-merged-branches/SKILL.md` for usage,",
|
|
11436
|
+
" output format, and the squash-merge verification algorithm.",
|
|
11437
|
+
"- `.claude/procedures/clean-merged-branches.sh` \u2014 analysis-only",
|
|
11438
|
+
" procedure for non-interactive agent use (orchestrator,",
|
|
11439
|
+
" maintenance-audit). NEVER deletes \u2014 only reports `MERGED` /",
|
|
11440
|
+
" `UNMERGED` / `EMPTY` / `SKIP_WORKTREE` lines."
|
|
11441
|
+
].join("\n"),
|
|
11442
|
+
tags: ["workflow"]
|
|
11443
|
+
}
|
|
11444
|
+
],
|
|
11445
|
+
skills: [cleanMergedBranchesSkill],
|
|
11446
|
+
procedures: [setIssueTypeProcedure, cleanMergedBranchesProcedure]
|
|
11447
|
+
};
|
|
11448
|
+
}
|
|
11449
|
+
var githubWorkflowBundle = buildGithubWorkflowBundle();
|
|
10998
11450
|
|
|
10999
11451
|
// src/agent/bundles/industry-discovery.ts
|
|
11000
11452
|
function buildIndustryDiscoveryAnalystSubAgent(paths, issueDefaults) {
|
|
@@ -15166,13 +15618,16 @@ function renderUnblockDependentsSection(ud) {
|
|
|
15166
15618
|
"",
|
|
15167
15619
|
"1. Searches open issues for `Depends on: #<closed>` references in",
|
|
15168
15620
|
" their body.",
|
|
15169
|
-
"2.
|
|
15621
|
+
"2. Skips any match carrying `status:deferred`, emitting a",
|
|
15622
|
+
" `SKIP_DEFERRED` line. A human-parked issue is never promoted by",
|
|
15623
|
+
" a sweep, no matter how its dependencies resolve.",
|
|
15624
|
+
"3. For each remaining match, re-reads every dependency listed across",
|
|
15170
15625
|
" **all** `Depends on:` lines in the body (bodies routinely list",
|
|
15171
15626
|
" one dependency per line) and checks whether they are all closed.",
|
|
15172
|
-
"
|
|
15627
|
+
"4. If **all** dependencies are closed, flips the dependent from",
|
|
15173
15628
|
" `status:blocked` to `status:ready` and posts a one-line comment",
|
|
15174
15629
|
" citing the resolving issue.",
|
|
15175
|
-
"
|
|
15630
|
+
"5. If **some** dependencies are still open, leaves the dependent",
|
|
15176
15631
|
" as `status:blocked` and optionally posts a partial-unblock",
|
|
15177
15632
|
" comment (see the **Partial unblock behaviour** subsection",
|
|
15178
15633
|
" below).",
|
|
@@ -15206,6 +15661,7 @@ function renderUnblockDependentsSection(ud) {
|
|
|
15206
15661
|
'UNBLOCKED #<dep> \u2014 all deps closed (<closed-list>) \u2014 "<title>"',
|
|
15207
15662
|
'UNBLOCK_FAILED #<dep> \u2014 label flip failed (all deps closed: <closed-list>) \u2014 "<title>"',
|
|
15208
15663
|
'STILL_BLOCKED #<dep> \u2014 waiting on <open-list> \u2014 "<title>"',
|
|
15664
|
+
'SKIP_DEFERRED #<dep> \u2014 status:deferred; human-parked, not promoting \u2014 "<title>"',
|
|
15209
15665
|
"NO_DEPENDENTS #<closed>",
|
|
15210
15666
|
"```",
|
|
15211
15667
|
"",
|
|
@@ -15215,7 +15671,10 @@ function renderUnblockDependentsSection(ud) {
|
|
|
15215
15671
|
"error, permissions, or the dependent went stale between the",
|
|
15216
15672
|
"search and the edit) \u2014 a human needs to retry or flip the label",
|
|
15217
15673
|
"manually. `STILL_BLOCKED` lines mean the dependent stays blocked",
|
|
15218
|
-
"pending other open deps. `
|
|
15674
|
+
"pending other open deps. `SKIP_DEFERRED` lines mean the dependent",
|
|
15675
|
+
"carries `status:deferred` and was deliberately left blocked even",
|
|
15676
|
+
"though its dependencies resolved \u2014 the sweep never promotes a",
|
|
15677
|
+
"human-parked issue. `NO_DEPENDENTS` means no open issue",
|
|
15219
15678
|
"references the just-closed issue in a `Depends on:` line.",
|
|
15220
15679
|
"",
|
|
15221
15680
|
"### Partial unblock behaviour",
|
|
@@ -15366,7 +15825,7 @@ function renderUnblockDependentsScript(ud) {
|
|
|
15366
15825
|
"# `status:blocked` \u2192 `status:ready` directly on the overflow.",
|
|
15367
15826
|
'dependents=$(gh issue list --label "status:blocked" --state open \\',
|
|
15368
15827
|
' --search "in:body \\"Depends on:\\"" \\',
|
|
15369
|
-
' --json number,title,body --limit 100 2>/dev/null || echo "[]")',
|
|
15828
|
+
' --json number,title,body,labels --limit 100 2>/dev/null || echo "[]")',
|
|
15370
15829
|
"",
|
|
15371
15830
|
`count=$(echo "$dependents" | jq 'length')`,
|
|
15372
15831
|
'if [[ "$count" -eq 0 ]]; then',
|
|
@@ -15374,6 +15833,18 @@ function renderUnblockDependentsScript(ud) {
|
|
|
15374
15833
|
" exit 0",
|
|
15375
15834
|
"fi",
|
|
15376
15835
|
"",
|
|
15836
|
+
"# Human-parked candidates (`status:deferred`). Collected jq-side into a",
|
|
15837
|
+
"# space-delimited lookup string rather than threaded through the",
|
|
15838
|
+
"# tab-separated records below: an extra TSV field would either sit after",
|
|
15839
|
+
"# dep_line (displacing the mandatory-last optional field) or before it",
|
|
15840
|
+
"# (reintroducing the #884 IFS tab-collapse bug). The skip itself happens",
|
|
15841
|
+
"# inside the loop, after the closed-issue reference test, so an unrelated",
|
|
15842
|
+
"# deferred issue in the search window never emits a line. No agent or",
|
|
15843
|
+
"# sweep ever removes `status:deferred` \u2014 only a human promotes it.",
|
|
15844
|
+
`deferred_set=" $(echo "$dependents" | jq -r '`,
|
|
15845
|
+
' .[] | select(.labels | map(.name) | index("status:deferred")) | .number',
|
|
15846
|
+
`' | tr '\\n' ' ')"`,
|
|
15847
|
+
"",
|
|
15377
15848
|
"# Union every `Depends on:` line per candidate (a body may list one",
|
|
15378
15849
|
"# dependency per line) into a single space-joined dep string and stream",
|
|
15379
15850
|
"# as tab-separated number / title / dep-line tuples.",
|
|
@@ -15409,6 +15880,14 @@ function renderUnblockDependentsScript(ud) {
|
|
|
15409
15880
|
"",
|
|
15410
15881
|
" found_any=true",
|
|
15411
15882
|
"",
|
|
15883
|
+
" # Deliberately-parked dependents never get promoted by a sweep, even",
|
|
15884
|
+
" # when every dependency has closed. Only a human clears",
|
|
15885
|
+
" # `status:deferred`.",
|
|
15886
|
+
' if [[ "$deferred_set" == *" ${num} "* ]]; then',
|
|
15887
|
+
' echo "SKIP_DEFERRED #${num} \u2014 status:deferred; human-parked, not promoting \u2014 \\"${title}\\""',
|
|
15888
|
+
" continue",
|
|
15889
|
+
" fi",
|
|
15890
|
+
"",
|
|
15412
15891
|
" # Re-check every dep in the list. Fully-closed \u2192 unblock.",
|
|
15413
15892
|
" all_closed=true",
|
|
15414
15893
|
' open_deps=""',
|
|
@@ -15598,15 +16077,26 @@ function buildCheckBlockedScript(tiers, scopeGate, _runRatio) {
|
|
|
15598
16077
|
" # position.",
|
|
15599
16078
|
" local issues",
|
|
15600
16079
|
' issues=$(gh issue list --label "status:blocked" --state open \\',
|
|
15601
|
-
' --json number,body --limit 1000 2>/dev/null || echo "[]")',
|
|
16080
|
+
' --json number,body,labels --limit 1000 2>/dev/null || echo "[]")',
|
|
15602
16081
|
"",
|
|
15603
16082
|
" local count",
|
|
15604
16083
|
` count=$(echo "$issues" | jq 'length')`,
|
|
15605
16084
|
' if [[ "$count" -eq 0 ]]; then',
|
|
15606
|
-
' echo "TRIAGE_DONE unblocked=0 still_blocked=0"',
|
|
16085
|
+
' echo "TRIAGE_DONE unblocked=0 still_blocked=0 deferred_skipped=0"',
|
|
15607
16086
|
" return 0",
|
|
15608
16087
|
" fi",
|
|
15609
16088
|
"",
|
|
16089
|
+
" # Human-parked candidates (`status:deferred`). Collected jq-side into",
|
|
16090
|
+
" # a space-delimited lookup string rather than threaded through the",
|
|
16091
|
+
" # tab-separated records below: an extra TSV field would either sit",
|
|
16092
|
+
" # after dep_line (displacing the mandatory-last optional field) or",
|
|
16093
|
+
" # before it (reintroducing the #884 IFS tab-collapse bug). No agent",
|
|
16094
|
+
" # or sweep ever removes `status:deferred` \u2014 only a human promotes it.",
|
|
16095
|
+
" local deferred_set",
|
|
16096
|
+
` deferred_set=" $(echo "$issues" | jq -r '`,
|
|
16097
|
+
' .[] | select(.labels | map(.name) | index("status:deferred")) | .number',
|
|
16098
|
+
` ' | tr '\\n' ' ')"`,
|
|
16099
|
+
"",
|
|
15610
16100
|
" local issue_data",
|
|
15611
16101
|
` issue_data=$(echo "$issues" | jq -r '`,
|
|
15612
16102
|
" .[] |",
|
|
@@ -15619,10 +16109,20 @@ function buildCheckBlockedScript(tiers, scopeGate, _runRatio) {
|
|
|
15619
16109
|
" # mirroring unblock-dependents.sh.",
|
|
15620
16110
|
" local unblocked_count=0",
|
|
15621
16111
|
" local still_blocked_count=0",
|
|
16112
|
+
" local deferred_skipped_count=0",
|
|
15622
16113
|
"",
|
|
15623
16114
|
" while IFS=$'\\t' read -r num dep_line; do",
|
|
15624
16115
|
' [[ -z "$num" ]] && continue',
|
|
15625
16116
|
"",
|
|
16117
|
+
" # Deliberately-parked issues never get promoted by a sweep, even",
|
|
16118
|
+
" # when every dependency has closed. Only a human clears",
|
|
16119
|
+
" # `status:deferred`.",
|
|
16120
|
+
' if [[ "$deferred_set" == *" ${num} "* ]]; then',
|
|
16121
|
+
' echo "SKIP_DEFERRED #${num} \u2014 status:deferred; human-parked, not promoting"',
|
|
16122
|
+
" deferred_skipped_count=$((deferred_skipped_count + 1))",
|
|
16123
|
+
" continue",
|
|
16124
|
+
" fi",
|
|
16125
|
+
"",
|
|
15626
16126
|
' if [[ -z "$dep_line" ]]; then',
|
|
15627
16127
|
' echo "BLOCKED #${num} \u2014 no Depends on field found"',
|
|
15628
16128
|
" still_blocked_count=$((still_blocked_count + 1))",
|
|
@@ -15683,7 +16183,7 @@ function buildCheckBlockedScript(tiers, scopeGate, _runRatio) {
|
|
|
15683
16183
|
' done <<< "$issue_data"',
|
|
15684
16184
|
"",
|
|
15685
16185
|
" # Single summary line consumed by the orchestrator.",
|
|
15686
|
-
' echo "TRIAGE_DONE unblocked=${unblocked_count} still_blocked=${still_blocked_count}"',
|
|
16186
|
+
' echo "TRIAGE_DONE unblocked=${unblocked_count} still_blocked=${still_blocked_count} deferred_skipped=${deferred_skipped_count}"',
|
|
15687
16187
|
"}",
|
|
15688
16188
|
"",
|
|
15689
16189
|
"cmd_eligible() {",
|
|
@@ -15707,11 +16207,26 @@ function buildCheckBlockedScript(tiers, scopeGate, _runRatio) {
|
|
|
15707
16207
|
" continue",
|
|
15708
16208
|
" fi",
|
|
15709
16209
|
"",
|
|
16210
|
+
" # Dispatch exclusions. `gh issue list` has no negative-label filter",
|
|
16211
|
+
" # for a label-filtered (non-search) listing, so both exclusions run",
|
|
16212
|
+
" # jq-side over the labels already fetched above \u2014 no new TSV field",
|
|
16213
|
+
" # is needed, and the mandatory-last dep_line ordering is untouched.",
|
|
16214
|
+
" # - `status:needs-attention` is additive (it no longer replaces the",
|
|
16215
|
+
" # base status), so a scope-gate-flagged issue keeps `status:ready`",
|
|
16216
|
+
" # and would re-surface in every scan until a human clears the flag",
|
|
16217
|
+
" # (#901). It is never dispatchable, so drop it from the scan.",
|
|
16218
|
+
" # - `status:deferred` is human-parked: captured for provenance and",
|
|
16219
|
+
" # never auto-dispatched. `status:ready` + `status:deferred` is",
|
|
16220
|
+
" # reachable (e.g. after an unblock or a manual edit), so exclude",
|
|
16221
|
+
" # it here as the dispatch-side half of the #887 guard.",
|
|
15710
16222
|
" local issue_data",
|
|
15711
16223
|
` issue_data=$(echo "$issues" | jq -r '`,
|
|
15712
16224
|
" .[] |",
|
|
16225
|
+
" (.labels | map(.name)) as $names |",
|
|
16226
|
+
' select($names | index("status:needs-attention") | not) |',
|
|
16227
|
+
' select($names | index("status:deferred") | not) |',
|
|
15713
16228
|
' (.body | split("\\n") | map(select(test("Depends on:"; "i"))) | join(" ")) as $dep_line |',
|
|
15714
|
-
' (
|
|
16229
|
+
' ($names | map(select(startswith("type:"))) | .[0] // "") as $type_label |',
|
|
15715
16230
|
' "\\(.number)\\t\\(.title)\\t\\($type_label)\\t\\($dep_line)"',
|
|
15716
16231
|
" ')",
|
|
15717
16232
|
"",
|
|
@@ -16355,7 +16870,7 @@ function buildCheckBlockedScript(tiers, scopeGate, _runRatio) {
|
|
|
16355
16870
|
function buildCheckBlockedProcedure(tiers, scopeGate = resolveScopeGate(), runRatio = resolveRunRatio()) {
|
|
16356
16871
|
return {
|
|
16357
16872
|
name: "check-blocked.sh",
|
|
16358
|
-
description: "Token-efficient issue triage script with subcommands: eligible, unblock, stale, orphaned, lease-reconcile, maintenance, prs, scope. Sorts eligible issues by priority desc \u2192 funnel tier asc \u2192 issue number asc
|
|
16873
|
+
description: "Token-efficient issue triage script with subcommands: eligible, unblock, stale, orphaned, lease-reconcile, maintenance, prs, scope. Sorts eligible issues by priority desc \u2192 funnel tier asc \u2192 issue number asc, excluding issues carrying `status:needs-attention` or `status:deferred`; the scope subcommand classifies a single issue against the scope-gate thresholds; the unblock subcommand applies the `status:blocked` \u2192 `status:ready` label flip itself, posts the canned unblock comment, skips human-parked `status:deferred` candidates with a `SKIP_DEFERRED` line, and emits a single `TRIAGE_DONE unblocked=N still_blocked=M deferred_skipped=K` summary line; the lease-reconcile subcommand auto-reconciles stuck `review:fixing` PR leases \u2014 re-applying `review:needs-worker` on an orphaned lease (fix-list stale, no worker report) so the Phase B1 drain retries, and removing `review:needs-worker` on a consumed-but-uncleared wedge (branch HEAD advanced past the fix-list, marker still set, no worker report) so the reviewer confirm pass can merge, always posting an audit-trail note comment and emitting a single `LEASE_RECONCILE orphaned=N consumed_uncleared=M` summary line; the maintenance subcommand flags stale issues with `status:needs-attention` (never auto-resets to `status:ready`), counts orphan branches/PRs, folds in the lease-reconcile sweep, and emits a `MAINTENANCE_DONE flagged_stale=N flagged_blocked=M orphan_branches=A orphan_prs=B needs_attention_total=T` summary line followed by the `LEASE_RECONCILE` line.",
|
|
16359
16874
|
content: buildCheckBlockedScript(tiers, scopeGate, runRatio)
|
|
16360
16875
|
};
|
|
16361
16876
|
}
|
|
@@ -17037,14 +17552,20 @@ var orchestratorSubAgent = {
|
|
|
17037
17552
|
"The script emits one summary line in this shape:",
|
|
17038
17553
|
"",
|
|
17039
17554
|
"```",
|
|
17040
|
-
"TRIAGE_DONE unblocked=<N> still_blocked=<M>",
|
|
17555
|
+
"TRIAGE_DONE unblocked=<N> still_blocked=<M> deferred_skipped=<K>",
|
|
17041
17556
|
"```",
|
|
17042
17557
|
"",
|
|
17043
17558
|
"Per-issue informational lines (`UNBLOCKED #N`, `UNBLOCK_FAILED #N`,",
|
|
17044
|
-
"`STILL_BLOCKED #N`, `BLOCKED #N \u2014 no Depends on
|
|
17045
|
-
"emitted for log visibility but are **not**
|
|
17046
|
-
"orchestrator \u2014 partial failures (one bad `gh`
|
|
17047
|
-
"the sweep, they are simply counted toward
|
|
17559
|
+
"`STILL_BLOCKED #N`, `SKIP_DEFERRED #N`, `BLOCKED #N \u2014 no Depends on",
|
|
17560
|
+
"field found`) are emitted for log visibility but are **not**",
|
|
17561
|
+
"load-bearing for the orchestrator \u2014 partial failures (one bad `gh`",
|
|
17562
|
+
"call) do not abort the sweep, they are simply counted toward",
|
|
17563
|
+
"`still_blocked`.",
|
|
17564
|
+
"",
|
|
17565
|
+
"`deferred_skipped` counts candidates the sweep deliberately left",
|
|
17566
|
+
"blocked because they carry `status:deferred`. Those issues are",
|
|
17567
|
+
"human-parked: no agent or sweep ever removes `status:deferred`, so",
|
|
17568
|
+
"a non-zero count is expected steady-state noise, not a failure.",
|
|
17048
17569
|
"",
|
|
17049
17570
|
"This phase is the **fallback safety net** for agent-driven",
|
|
17050
17571
|
"unblocking. Every agent that applies `status:done` already runs",
|
|
@@ -18224,9 +18745,11 @@ var checkBlockedCommand = {
|
|
|
18224
18745
|
"reference, applies the `status:blocked` \u2192 `status:ready` label flip",
|
|
18225
18746
|
"itself, posts the canned `Dependencies resolved \u2014 unblocking.`",
|
|
18226
18747
|
"comment, and emits a single",
|
|
18227
|
-
"`TRIAGE_DONE unblocked=<N> still_blocked=<M>`
|
|
18228
|
-
"
|
|
18229
|
-
"
|
|
18748
|
+
"`TRIAGE_DONE unblocked=<N> still_blocked=<M> deferred_skipped=<K>`",
|
|
18749
|
+
"summary line. Candidates carrying `status:deferred` are skipped",
|
|
18750
|
+
"rather than promoted \u2014 only a human clears that label. Per-issue",
|
|
18751
|
+
"informational lines (`UNBLOCKED`, `UNBLOCK_FAILED`, `STILL_BLOCKED`,",
|
|
18752
|
+
"`SKIP_DEFERRED`) are also emitted for log visibility.",
|
|
18230
18753
|
"",
|
|
18231
18754
|
"Summarise the output (the `TRIAGE_DONE` counts and the first few",
|
|
18232
18755
|
"per-issue lines) \u2014 do **not** apply additional label flips yourself;",
|
|
@@ -31425,429 +31948,56 @@ function buildStandardsResearchBundle(paths = DEFAULT_AGENT_PATHS, issueDefaults
|
|
|
31425
31948
|
}
|
|
31426
31949
|
var standardsResearchBundle = buildStandardsResearchBundle();
|
|
31427
31950
|
|
|
31428
|
-
// src/
|
|
31429
|
-
|
|
31430
|
-
|
|
31431
|
-
|
|
31432
|
-
// src/turbo/turbo-repo-task.ts
|
|
31433
|
-
var import_lib = require("projen/lib");
|
|
31434
|
-
var TurboRepoTask = class extends import_lib.Component {
|
|
31435
|
-
constructor(project, options) {
|
|
31436
|
-
super(project);
|
|
31437
|
-
this.project = project;
|
|
31438
|
-
this.name = options.name;
|
|
31439
|
-
this.dependsOn = options.dependsOn ?? [];
|
|
31440
|
-
this.env = options.env ?? [];
|
|
31441
|
-
this.passThroughEnv = options.passThroughEnv ?? [];
|
|
31442
|
-
this.outputs = options.outputs ?? [];
|
|
31443
|
-
this.cache = options.cache ?? true;
|
|
31444
|
-
this.inputs = [
|
|
31445
|
-
...options.inputs ?? [],
|
|
31446
|
-
// rerun if projen config changes
|
|
31447
|
-
".projen/**",
|
|
31448
|
-
// ignore mac files
|
|
31449
|
-
"!.DS_Store",
|
|
31450
|
-
"!**/.DS_Store"
|
|
31451
|
-
];
|
|
31452
|
-
this.outputLogs = options.outputLogs ?? "new-only";
|
|
31453
|
-
this.persistent = options.persistent ?? false;
|
|
31454
|
-
this.interactive = options.interactive ?? false;
|
|
31455
|
-
this.isActive = true;
|
|
31456
|
-
}
|
|
31457
|
-
taskConfig() {
|
|
31458
|
-
return {
|
|
31459
|
-
dependsOn: this.dependsOn,
|
|
31460
|
-
env: this.env,
|
|
31461
|
-
passThroughEnv: this.passThroughEnv,
|
|
31462
|
-
outputs: this.outputs,
|
|
31463
|
-
cache: this.cache,
|
|
31464
|
-
inputs: this.inputs,
|
|
31465
|
-
outputLogs: this.outputLogs,
|
|
31466
|
-
persistent: this.persistent,
|
|
31467
|
-
interactive: this.interactive
|
|
31468
|
-
};
|
|
31469
|
-
}
|
|
31470
|
-
};
|
|
31471
|
-
|
|
31472
|
-
// src/turbo/turbo-repo.ts
|
|
31473
|
-
var ROOT_TURBO_TASK_NAME = "turbo:build";
|
|
31474
|
-
var ROOT_CI_TASK_NAME = "build:all";
|
|
31475
|
-
var _TurboRepo = class _TurboRepo extends import_lib2.Component {
|
|
31476
|
-
constructor(project, options = {}) {
|
|
31477
|
-
super(project);
|
|
31478
|
-
this.project = project;
|
|
31479
|
-
/**
|
|
31480
|
-
* Sub-Tasks to run
|
|
31481
|
-
*/
|
|
31482
|
-
this.tasks = [];
|
|
31483
|
-
this.turboVersion = options.turboVersion ?? "catalog:";
|
|
31484
|
-
this.isRootProject = project === project.root;
|
|
31485
|
-
if (this.isRootProject) {
|
|
31486
|
-
project.addDevDeps(`turbo@${this.turboVersion}`);
|
|
31487
|
-
}
|
|
31488
|
-
project.gitignore.addPatterns("/.turbo");
|
|
31489
|
-
project.npmignore?.addPatterns("/.turbo/");
|
|
31490
|
-
this.extends = options.extends ?? (this.isRootProject ? [] : ["//"]);
|
|
31491
|
-
this.globalDependencies = options.globalDependencies ?? [];
|
|
31492
|
-
this.globalEnv = options.globalEnv ?? [];
|
|
31493
|
-
this.globalPassThroughEnv = options.globalPassThroughEnv ?? [];
|
|
31494
|
-
this.ui = options.ui ?? "stream";
|
|
31495
|
-
this.dangerouslyDisablePackageManagerCheck = options.dangerouslyDisablePackageManagerCheck ?? false;
|
|
31496
|
-
this.cacheDir = options.cacheDir ?? ".turbo/cache";
|
|
31497
|
-
this.daemon = options.daemon ?? true;
|
|
31498
|
-
this.envMode = options.envMode ?? "strict";
|
|
31499
|
-
this.runOptions = {
|
|
31500
|
-
...options.runOptions,
|
|
31501
|
-
summarize: options.runOptions?.summarize ?? true,
|
|
31502
|
-
concurrency: options.runOptions?.concurrency ?? 10
|
|
31503
|
-
};
|
|
31504
|
-
this.remoteCacheOptions = options.remoteCacheOptions;
|
|
31505
|
-
this.buildAllTaskEnvVars = options.buildAllTaskEnvVars ?? {};
|
|
31506
|
-
this.buildTask = new TurboRepoTask(this.project, {
|
|
31507
|
-
name: ROOT_TURBO_TASK_NAME,
|
|
31508
|
-
dependsOn: this.isRootProject ? [`^${ROOT_TURBO_TASK_NAME}`] : []
|
|
31509
|
-
});
|
|
31510
|
-
if (this.isRootProject) {
|
|
31511
|
-
this.buildAllTask = this.project.tasks.addTask(ROOT_CI_TASK_NAME, {
|
|
31512
|
-
description: "Root build followed by sub-project builds. Mimics the CI build process in one step."
|
|
31513
|
-
});
|
|
31514
|
-
this.buildAllTask.exec("turbo telemetry disable");
|
|
31515
|
-
if (this.buildAllTaskEnvVars) {
|
|
31516
|
-
Object.entries(this.buildAllTaskEnvVars).forEach(([name, value]) => {
|
|
31517
|
-
this.addGlobalEnvVar(name, value);
|
|
31518
|
-
});
|
|
31519
|
-
}
|
|
31520
|
-
if (!this.remoteCacheOptions) {
|
|
31521
|
-
this.buildAllTask.exec(
|
|
31522
|
-
`turbo ${ROOT_TURBO_TASK_NAME} ${this.renderRunArgs(false)}`
|
|
31523
|
-
);
|
|
31524
|
-
} else {
|
|
31525
|
-
this.buildAllTask.exec(
|
|
31526
|
-
`turbo ${ROOT_TURBO_TASK_NAME} ${this.renderRunArgs(true)}`,
|
|
31527
|
-
{
|
|
31528
|
-
condition: '[ ! -n "$CI" ]',
|
|
31529
|
-
env: {
|
|
31530
|
-
TURBO_ENDPOINT: `$(aws ssm get-parameter --name ${this.remoteCacheOptions.endpointParamName} --query Parameter.Value --output text --profile ${this.remoteCacheOptions.profileName})`,
|
|
31531
|
-
TURBO_TOKEN: `$(aws ssm get-parameter --name ${this.remoteCacheOptions.tokenParamName} --query Parameter.Value --output text --profile ${this.remoteCacheOptions.profileName})`
|
|
31532
|
-
}
|
|
31533
|
-
}
|
|
31534
|
-
);
|
|
31535
|
-
this.buildAllTask.exec(
|
|
31536
|
-
`turbo ${ROOT_TURBO_TASK_NAME} ${this.renderRunArgs(true)}`,
|
|
31537
|
-
{
|
|
31538
|
-
condition: '[ -n "$CI" ]',
|
|
31539
|
-
env: {
|
|
31540
|
-
TURBO_ENDPOINT: `$(aws ssm get-parameter --name ${this.remoteCacheOptions.endpointParamName} --query Parameter.Value --output text)`,
|
|
31541
|
-
TURBO_TOKEN: `$(aws ssm get-parameter --name ${this.remoteCacheOptions.tokenParamName} --query Parameter.Value --output text)`
|
|
31542
|
-
}
|
|
31543
|
-
}
|
|
31544
|
-
);
|
|
31545
|
-
}
|
|
31546
|
-
}
|
|
31547
|
-
if (!this.isRootProject) {
|
|
31548
|
-
this.preCompileTask = new TurboRepoTask(project, {
|
|
31549
|
-
name: options.preCompileTask?.name ?? "pre-compile",
|
|
31550
|
-
inputs: ["src/**"]
|
|
31551
|
-
});
|
|
31552
|
-
this.compileTask = new TurboRepoTask(project, {
|
|
31553
|
-
name: options.compileTask?.name ?? "compile",
|
|
31554
|
-
inputs: ["src/**"]
|
|
31555
|
-
});
|
|
31556
|
-
this.postCompileTask = new TurboRepoTask(project, {
|
|
31557
|
-
name: options.postCompileTask?.name ?? "post-compile",
|
|
31558
|
-
inputs: ["src/**"]
|
|
31559
|
-
});
|
|
31560
|
-
this.testTask = new TurboRepoTask(project, {
|
|
31561
|
-
name: options.testTask?.name ?? "test"
|
|
31562
|
-
});
|
|
31563
|
-
this.packageTask = new TurboRepoTask(project, {
|
|
31564
|
-
name: options.packageTask?.name ?? "package",
|
|
31565
|
-
inputs: [".npmignore"]
|
|
31566
|
-
});
|
|
31567
|
-
this.tasks.push(
|
|
31568
|
-
this.preCompileTask,
|
|
31569
|
-
this.compileTask,
|
|
31570
|
-
this.postCompileTask,
|
|
31571
|
-
this.testTask,
|
|
31572
|
-
this.packageTask
|
|
31573
|
-
);
|
|
31574
|
-
}
|
|
31575
|
-
}
|
|
31576
|
-
/**
|
|
31577
|
-
* Static method to discovert turbo in a project.
|
|
31578
|
-
*/
|
|
31579
|
-
static of(project) {
|
|
31580
|
-
const isDefined = (c) => c instanceof _TurboRepo;
|
|
31581
|
-
return project.components.find(isDefined);
|
|
31582
|
-
}
|
|
31583
|
-
/**
|
|
31584
|
-
* Render the `turbo run` CLI flag string for the `build:all` / `reset:all`
|
|
31585
|
-
* task commands from {@link runOptions}. With no `runOptions` configured the
|
|
31586
|
-
* output matches the historically hard-coded flags exactly.
|
|
31587
|
-
*
|
|
31588
|
-
* @param remote - when `true`, also emit the remote-cache flags
|
|
31589
|
-
* (`--cache=remote:rw` plus `--api` / `--token` / `--team` derived from
|
|
31590
|
-
* {@link remoteCacheOptions}). The remote-cache `build:all` variant passes
|
|
31591
|
-
* `true`; `reset:all` and the local `build:all` variant pass `false`.
|
|
31592
|
-
*/
|
|
31593
|
-
renderRunArgs(remote) {
|
|
31594
|
-
const run = this.runOptions;
|
|
31595
|
-
const args = [];
|
|
31596
|
-
if (run.summarize) {
|
|
31597
|
-
args.push("--summarize");
|
|
31598
|
-
}
|
|
31599
|
-
args.push(`--concurrency=${run.concurrency}`);
|
|
31600
|
-
if (run.force) {
|
|
31601
|
-
args.push("--force");
|
|
31602
|
-
}
|
|
31603
|
-
if (run.noCache) {
|
|
31604
|
-
args.push("--no-cache");
|
|
31605
|
-
}
|
|
31606
|
-
if (run.only) {
|
|
31607
|
-
args.push("--only");
|
|
31608
|
-
}
|
|
31609
|
-
if (run.affected) {
|
|
31610
|
-
args.push("--affected");
|
|
31611
|
-
}
|
|
31612
|
-
if (run.cacheWorkers !== void 0) {
|
|
31613
|
-
args.push(`--cache-workers=${run.cacheWorkers}`);
|
|
31614
|
-
}
|
|
31615
|
-
if (run.continueOn !== void 0) {
|
|
31616
|
-
args.push(`--continue=${run.continueOn}`);
|
|
31617
|
-
}
|
|
31618
|
-
if (run.frameworkInference !== void 0) {
|
|
31619
|
-
args.push(`--framework-inference=${run.frameworkInference}`);
|
|
31620
|
-
}
|
|
31621
|
-
for (const filter of run.filter ?? []) {
|
|
31622
|
-
args.push(`--filter=${filter}`);
|
|
31623
|
-
}
|
|
31624
|
-
if (run.outputLogs !== void 0) {
|
|
31625
|
-
args.push(`--output-logs=${run.outputLogs}`);
|
|
31626
|
-
}
|
|
31627
|
-
if (run.logOrder !== void 0) {
|
|
31628
|
-
args.push(`--log-order=${run.logOrder}`);
|
|
31629
|
-
}
|
|
31630
|
-
if (run.logPrefix !== void 0) {
|
|
31631
|
-
args.push(`--log-prefix=${run.logPrefix}`);
|
|
31632
|
-
}
|
|
31633
|
-
if (run.dryRun !== void 0) {
|
|
31634
|
-
args.push(`--dry-run=${run.dryRun}`);
|
|
31635
|
-
}
|
|
31636
|
-
const cache = run.cache ?? (remote ? "remote:rw" : void 0);
|
|
31637
|
-
if (cache !== void 0) {
|
|
31638
|
-
args.push(`--cache=${cache}`);
|
|
31639
|
-
}
|
|
31640
|
-
if (remote && this.remoteCacheOptions) {
|
|
31641
|
-
args.push(
|
|
31642
|
-
"--api=$TURBO_ENDPOINT",
|
|
31643
|
-
"--token=$TURBO_TOKEN",
|
|
31644
|
-
`--team=${this.remoteCacheOptions.teamName}`
|
|
31645
|
-
);
|
|
31646
|
-
}
|
|
31647
|
-
if (run.additionalArgs) {
|
|
31648
|
-
args.push(...run.additionalArgs);
|
|
31649
|
-
}
|
|
31650
|
-
return args.join(" ");
|
|
31651
|
-
}
|
|
31652
|
-
/**
|
|
31653
|
-
* Add an env var to the global env vars for all tasks.
|
|
31654
|
-
* This will also become an input for the build:all task cache at the root.
|
|
31655
|
-
*/
|
|
31656
|
-
addGlobalEnvVar(name, value) {
|
|
31657
|
-
this.buildAllTask?.env(name, value);
|
|
31658
|
-
if (this.isRootProject) {
|
|
31659
|
-
this.globalEnv.push(name);
|
|
31660
|
-
}
|
|
31661
|
-
}
|
|
31662
|
-
activateBranchNameEnvVar(options) {
|
|
31663
|
-
const value = '$([ -n "$GIT_BRANCH_NAME" ] && echo "$GIT_BRANCH_NAME" || git rev-parse --abbrev-ref HEAD)';
|
|
31664
|
-
if (options === void 0) {
|
|
31665
|
-
this.project.logger.warn(
|
|
31666
|
-
"TurboRepo.activateBranchNameEnvVar() with no arguments is deprecated. It writes GIT_BRANCH_NAME to the root `globalEnv`, which forces every task in the monorepo to miss cache on every branch switch. Pass `{ tasks: [...] }` and name only the tasks that actually consume the branch (e.g. CDK synth/package) to preserve cross-branch cache hits for everything else."
|
|
31667
|
-
);
|
|
31668
|
-
this.addGlobalEnvVar("GIT_BRANCH_NAME", value);
|
|
31669
|
-
return;
|
|
31670
|
-
}
|
|
31671
|
-
const knownTaskNames = this.tasks.map((task) => task.name);
|
|
31672
|
-
const unknown = options.tasks.filter(
|
|
31673
|
-
(name) => !knownTaskNames.includes(name)
|
|
31674
|
-
);
|
|
31675
|
-
if (unknown.length > 0) {
|
|
31676
|
-
throw new Error(
|
|
31677
|
-
`TurboRepo.activateBranchNameEnvVar: unknown task name(s) ${JSON.stringify(
|
|
31678
|
-
unknown
|
|
31679
|
-
)}. Known tasks on this TurboRepo: ${JSON.stringify(knownTaskNames)}.`
|
|
31680
|
-
);
|
|
31681
|
-
}
|
|
31682
|
-
for (const name of options.tasks) {
|
|
31683
|
-
const task = this.tasks.find((t) => t.name === name);
|
|
31684
|
-
if (task && !task.env.includes("GIT_BRANCH_NAME")) {
|
|
31685
|
-
task.env.push("GIT_BRANCH_NAME");
|
|
31686
|
-
}
|
|
31687
|
-
}
|
|
31688
|
-
}
|
|
31689
|
-
/**
|
|
31690
|
-
* Paths of all generated files in the project, deduped, for use as task
|
|
31691
|
-
* inputs so the compile cache invalidates when they change. Includes
|
|
31692
|
-
* projen-managed `FileBase` files plus generated-once `SampleFile` /
|
|
31693
|
-
* `SampleDir` — whose paths projen keeps private, so they are read defensively
|
|
31694
|
-
* and skipped if that internal shape ever changes. Computed at synth time so
|
|
31695
|
-
* files added after this component (e.g. a subclass's SampleFiles) are seen.
|
|
31696
|
-
*/
|
|
31697
|
-
generatedFileInputs() {
|
|
31698
|
-
const inputs = /* @__PURE__ */ new Set();
|
|
31699
|
-
for (const component of this.project.components) {
|
|
31700
|
-
if (component instanceof import_lib2.FileBase) {
|
|
31701
|
-
inputs.add(component.path);
|
|
31702
|
-
} else if (component instanceof import_lib2.SampleFile) {
|
|
31703
|
-
const filePath = component.filePath;
|
|
31704
|
-
if (typeof filePath === "string") {
|
|
31705
|
-
inputs.add(filePath);
|
|
31706
|
-
}
|
|
31707
|
-
} else if (component instanceof import_lib2.SampleDir) {
|
|
31708
|
-
const dir = component.dir;
|
|
31709
|
-
if (typeof dir === "string") {
|
|
31710
|
-
inputs.add(`${dir}/**`);
|
|
31711
|
-
}
|
|
31712
|
-
}
|
|
31713
|
-
}
|
|
31714
|
-
return Array.from(inputs);
|
|
31715
|
-
}
|
|
31716
|
-
preSynthesize() {
|
|
31717
|
-
let nextDependsOn = this.project.deps.all.filter((d) => d.version === "workspace:*").map((d) => [d.name, ROOT_TURBO_TASK_NAME].join("#"));
|
|
31718
|
-
if (!this.isRootProject) {
|
|
31719
|
-
[
|
|
31720
|
-
[this.project.preCompileTask, this.preCompileTask],
|
|
31721
|
-
[this.project.compileTask, this.compileTask],
|
|
31722
|
-
[this.project.postCompileTask, this.postCompileTask],
|
|
31723
|
-
[this.project.testTask, this.testTask],
|
|
31724
|
-
[this.project.packageTask, this.packageTask]
|
|
31725
|
-
].forEach(([pjTask, turboTask]) => {
|
|
31726
|
-
if (pjTask && turboTask && pjTask.steps.length > 0) {
|
|
31727
|
-
if (nextDependsOn.length > 0) {
|
|
31728
|
-
turboTask.dependsOn.push(...nextDependsOn);
|
|
31729
|
-
}
|
|
31730
|
-
nextDependsOn = [turboTask.name];
|
|
31731
|
-
} else {
|
|
31732
|
-
turboTask.isActive = false;
|
|
31733
|
-
}
|
|
31734
|
-
});
|
|
31735
|
-
this.buildTask.dependsOn.push(...nextDependsOn);
|
|
31736
|
-
}
|
|
31737
|
-
const generatedInputs = this.generatedFileInputs();
|
|
31738
|
-
const appendGeneratedInputs = (task) => {
|
|
31739
|
-
if (!task) {
|
|
31740
|
-
return;
|
|
31741
|
-
}
|
|
31742
|
-
for (const input of generatedInputs) {
|
|
31743
|
-
if (!task.inputs.includes(input)) {
|
|
31744
|
-
task.inputs.push(input);
|
|
31745
|
-
}
|
|
31746
|
-
}
|
|
31747
|
-
};
|
|
31748
|
-
if (this.isRootProject) {
|
|
31749
|
-
appendGeneratedInputs(this.buildTask);
|
|
31750
|
-
} else {
|
|
31751
|
-
appendGeneratedInputs(this.preCompileTask);
|
|
31752
|
-
appendGeneratedInputs(this.compileTask);
|
|
31753
|
-
appendGeneratedInputs(this.postCompileTask);
|
|
31754
|
-
}
|
|
31755
|
-
const fileName = "turbo.json";
|
|
31756
|
-
this.project.addPackageIgnore(fileName);
|
|
31757
|
-
new import_lib2.JsonFile(this.project, fileName, {
|
|
31758
|
-
obj: {
|
|
31759
|
-
extends: this.extends.length ? this.extends : void 0,
|
|
31760
|
-
globalDependencies: this.isRootProject && this.globalDependencies.length ? this.globalDependencies : void 0,
|
|
31761
|
-
globalEnv: this.isRootProject && this.globalEnv.length ? this.globalEnv : void 0,
|
|
31762
|
-
globalPassThroughEnv: this.isRootProject && this.globalPassThroughEnv.length ? this.globalPassThroughEnv : void 0,
|
|
31763
|
-
ui: this.isRootProject ? this.ui : void 0,
|
|
31764
|
-
dangerouslyDisablePackageManagerCheck: this.isRootProject ? this.dangerouslyDisablePackageManagerCheck : void 0,
|
|
31765
|
-
cacheDir: this.isRootProject ? this.cacheDir : void 0,
|
|
31766
|
-
envMode: this.isRootProject ? this.envMode : void 0,
|
|
31767
|
-
/**
|
|
31768
|
-
* All tasks
|
|
31769
|
-
*/
|
|
31770
|
-
tasks: this.tasks.filter((task) => task.isActive).reduce(
|
|
31771
|
-
(acc, task) => {
|
|
31772
|
-
acc[task.name] = {
|
|
31773
|
-
...task.taskConfig()
|
|
31774
|
-
};
|
|
31775
|
-
return acc;
|
|
31776
|
-
},
|
|
31777
|
-
{
|
|
31778
|
-
[this.buildTask.name]: { ...this.buildTask.taskConfig() }
|
|
31779
|
-
}
|
|
31780
|
-
)
|
|
31781
|
-
}
|
|
31782
|
-
});
|
|
31783
|
-
super.preSynthesize();
|
|
31951
|
+
// src/agent/bundles/turborepo.ts
|
|
31952
|
+
function renderCachingBullet(policy) {
|
|
31953
|
+
if (policy.remoteCacheEnabled && policy.awsProfileName) {
|
|
31954
|
+
return `- Uses remote caching (requires AWS credentials on the \`${policy.awsProfileName}\` profile)`;
|
|
31784
31955
|
}
|
|
31785
|
-
|
|
31786
|
-
|
|
31956
|
+
return "- Local caching only \u2014 no remote cache is configured, so no AWS credentials are required";
|
|
31957
|
+
}
|
|
31958
|
+
function buildTurborepoBundle(buildPolicy = DEFAULT_BUILD_POLICY) {
|
|
31787
31959
|
return {
|
|
31788
|
-
|
|
31789
|
-
|
|
31790
|
-
|
|
31791
|
-
|
|
31792
|
-
contents: import_workflows_model.JobPermission.WRITE,
|
|
31793
|
-
idToken: import_workflows_model.JobPermission.WRITE
|
|
31794
|
-
},
|
|
31795
|
-
preBuildSteps: [
|
|
31960
|
+
name: "turborepo",
|
|
31961
|
+
description: "Turborepo workspace rules and task pipeline conventions",
|
|
31962
|
+
appliesWhen: (project) => hasComponent(project, TurboRepo),
|
|
31963
|
+
rules: [
|
|
31796
31964
|
{
|
|
31797
|
-
name: "
|
|
31798
|
-
|
|
31799
|
-
|
|
31800
|
-
|
|
31801
|
-
|
|
31802
|
-
|
|
31803
|
-
|
|
31965
|
+
name: "turborepo-conventions",
|
|
31966
|
+
description: "Turborepo build system and task pipeline conventions",
|
|
31967
|
+
scope: AGENT_RULE_SCOPE.FILE_PATTERN,
|
|
31968
|
+
filePatterns: ["turbo.json", "package.json"],
|
|
31969
|
+
content: [
|
|
31970
|
+
"# Turborepo Conventions",
|
|
31971
|
+
"",
|
|
31972
|
+
"## Build System",
|
|
31973
|
+
"",
|
|
31974
|
+
"- **Build**: `pnpm build:all` (uses Turborepo)",
|
|
31975
|
+
"- **Test**: `pnpm test` or `pnpm test:watch`",
|
|
31976
|
+
"- **Lint**: `pnpm eslint`",
|
|
31977
|
+
"",
|
|
31978
|
+
"## Task Pipeline",
|
|
31979
|
+
"",
|
|
31980
|
+
renderCachingBullet(buildPolicy),
|
|
31981
|
+
"- Only rebuilds changed packages",
|
|
31982
|
+
"- Cache key based on file hashes and dependency graph",
|
|
31983
|
+
"- Configured in `turbo.json`",
|
|
31984
|
+
"",
|
|
31985
|
+
"## Workspace Rules",
|
|
31986
|
+
"",
|
|
31987
|
+
"- Source files: `src/` directory",
|
|
31988
|
+
"- Tests: Co-located with source files (`.spec.ts` or `.test.ts`)",
|
|
31989
|
+
"- Exports: Use `index.ts` files for clean public APIs",
|
|
31990
|
+
"- Configuration: Managed by Projen (edit `.projenrc.ts` or `projenrc/*.ts`)"
|
|
31991
|
+
].join("\n"),
|
|
31992
|
+
tags: ["workflow"]
|
|
31804
31993
|
}
|
|
31805
|
-
]
|
|
31806
|
-
|
|
31807
|
-
|
|
31808
|
-
var TurboRepo = _TurboRepo;
|
|
31809
|
-
|
|
31810
|
-
// src/agent/bundles/turborepo.ts
|
|
31811
|
-
var turborepoBundle = {
|
|
31812
|
-
name: "turborepo",
|
|
31813
|
-
description: "Turborepo workspace rules and task pipeline conventions",
|
|
31814
|
-
appliesWhen: (project) => hasComponent(project, TurboRepo),
|
|
31815
|
-
rules: [
|
|
31816
|
-
{
|
|
31817
|
-
name: "turborepo-conventions",
|
|
31818
|
-
description: "Turborepo build system and task pipeline conventions",
|
|
31819
|
-
scope: AGENT_RULE_SCOPE.FILE_PATTERN,
|
|
31820
|
-
filePatterns: ["turbo.json", "package.json"],
|
|
31821
|
-
content: [
|
|
31822
|
-
"# Turborepo Conventions",
|
|
31823
|
-
"",
|
|
31824
|
-
"## Build System",
|
|
31825
|
-
"",
|
|
31826
|
-
"- **Build**: `pnpm build:all` (uses Turborepo)",
|
|
31827
|
-
"- **Test**: `pnpm test` or `pnpm test:watch`",
|
|
31828
|
-
"- **Lint**: `pnpm eslint`",
|
|
31829
|
-
"",
|
|
31830
|
-
"## Task Pipeline",
|
|
31831
|
-
"",
|
|
31832
|
-
"- Uses remote caching (requires AWS credentials)",
|
|
31833
|
-
"- Only rebuilds changed packages",
|
|
31834
|
-
"- Cache key based on file hashes and dependency graph",
|
|
31835
|
-
"- Configured in `turbo.json`",
|
|
31836
|
-
"",
|
|
31837
|
-
"## Workspace Rules",
|
|
31838
|
-
"",
|
|
31839
|
-
"- Source files: `src/` directory",
|
|
31840
|
-
"- Tests: Co-located with source files (`.spec.ts` or `.test.ts`)",
|
|
31841
|
-
"- Exports: Use `index.ts` files for clean public APIs",
|
|
31842
|
-
"- Configuration: Managed by Projen (edit `.projenrc.ts` or `projenrc/*.ts`)"
|
|
31843
|
-
].join("\n"),
|
|
31844
|
-
tags: ["workflow"]
|
|
31994
|
+
],
|
|
31995
|
+
claudePermissions: {
|
|
31996
|
+
allow: ["Bash(npx turbo:*)"]
|
|
31845
31997
|
}
|
|
31846
|
-
|
|
31847
|
-
|
|
31848
|
-
|
|
31849
|
-
}
|
|
31850
|
-
};
|
|
31998
|
+
};
|
|
31999
|
+
}
|
|
32000
|
+
var turborepoBundle = buildTurborepoBundle();
|
|
31851
32001
|
|
|
31852
32002
|
// src/agent/bundles/typescript.ts
|
|
31853
32003
|
var typescriptBundle = {
|
|
@@ -33062,7 +33212,7 @@ function renderPriorityRulesSection(rules) {
|
|
|
33062
33212
|
}
|
|
33063
33213
|
|
|
33064
33214
|
// src/agent/bundles/index.ts
|
|
33065
|
-
function buildBuiltInBundles(paths = DEFAULT_AGENT_PATHS, issueDefaults = DEFAULT_RESOLVED_ISSUE_DEFAULTS, defaultAgentTier = AGENT_MODEL.BALANCED, bundleAgentTiers = /* @__PURE__ */ new Map(), prReviewPolicy = resolvePrReviewPolicy()) {
|
|
33215
|
+
function buildBuiltInBundles(paths = DEFAULT_AGENT_PATHS, issueDefaults = DEFAULT_RESOLVED_ISSUE_DEFAULTS, defaultAgentTier = AGENT_MODEL.BALANCED, bundleAgentTiers = /* @__PURE__ */ new Map(), prReviewPolicy = resolvePrReviewPolicy(), buildPolicy = DEFAULT_BUILD_POLICY) {
|
|
33066
33216
|
const tierFor = (bundle) => bundleAgentTiers.get(bundle) ?? defaultAgentTier;
|
|
33067
33217
|
return [
|
|
33068
33218
|
buildBaseBundle(paths),
|
|
@@ -33070,11 +33220,11 @@ function buildBuiltInBundles(paths = DEFAULT_AGENT_PATHS, issueDefaults = DEFAUL
|
|
|
33070
33220
|
typescriptBundle,
|
|
33071
33221
|
vitestBundle,
|
|
33072
33222
|
jestBundle,
|
|
33073
|
-
|
|
33223
|
+
buildTurborepoBundle(buildPolicy),
|
|
33074
33224
|
pnpmBundle,
|
|
33075
33225
|
awsCdkBundle,
|
|
33076
33226
|
projenBundle,
|
|
33077
|
-
|
|
33227
|
+
buildGithubWorkflowBundle(buildPolicy),
|
|
33078
33228
|
slackBundle,
|
|
33079
33229
|
buildMeetingAnalysisBundle(tierFor("meeting-analysis")),
|
|
33080
33230
|
agendaBundle,
|
|
@@ -34159,6 +34309,13 @@ var AgentConfig = class _AgentConfig extends import_projen8.Component {
|
|
|
34159
34309
|
* their rendered rule content reflects any consumer override.
|
|
34160
34310
|
* Bundles that do not read agent paths are passed through as-is
|
|
34161
34311
|
* from their default const exports.
|
|
34312
|
+
*
|
|
34313
|
+
* The build policy is auto-detected from the project's `TurboRepo`
|
|
34314
|
+
* component here rather than configured, so build guidance in the
|
|
34315
|
+
* `github-workflow` and `turborepo` rules only claims an AWS
|
|
34316
|
+
* credential requirement when a remote cache actually exists. The
|
|
34317
|
+
* getter is lazy by design — `TurboRepo` must already be attached
|
|
34318
|
+
* to the project when the bundles are first read.
|
|
34162
34319
|
*/
|
|
34163
34320
|
get pathAwareBundles() {
|
|
34164
34321
|
if (!this.cachedBundles) {
|
|
@@ -34167,7 +34324,8 @@ var AgentConfig = class _AgentConfig extends import_projen8.Component {
|
|
|
34167
34324
|
resolveIssueDefaults(this.options.issueDefaults),
|
|
34168
34325
|
resolveDefaultAgentTier(this.options),
|
|
34169
34326
|
resolveBundleAgentTiers(this.options),
|
|
34170
|
-
resolvePrReviewPolicy(this.options.prReviewPolicy)
|
|
34327
|
+
resolvePrReviewPolicy(this.options.prReviewPolicy),
|
|
34328
|
+
resolveBuildPolicy(this.project)
|
|
34171
34329
|
);
|
|
34172
34330
|
}
|
|
34173
34331
|
return this.cachedBundles;
|
|
@@ -40873,6 +41031,7 @@ export const collections = {
|
|
|
40873
41031
|
DEFAULT_API_EXTRACTOR_REPORT_FILENAME,
|
|
40874
41032
|
DEFAULT_API_EXTRACTOR_REPORT_FOLDER,
|
|
40875
41033
|
DEFAULT_AUDIT_REPORT_DIR,
|
|
41034
|
+
DEFAULT_BUILD_POLICY,
|
|
40876
41035
|
DEFAULT_BUNDLE_OVERRIDES,
|
|
40877
41036
|
DEFAULT_DECOMPOSITION_TEMPLATE,
|
|
40878
41037
|
DEFAULT_DISPATCH_MODEL,
|
|
@@ -40993,6 +41152,7 @@ export const collections = {
|
|
|
40993
41152
|
buildCompanyProfileBundle,
|
|
40994
41153
|
buildCustomerProfileBundle,
|
|
40995
41154
|
buildDocsSyncBundle,
|
|
41155
|
+
buildGithubWorkflowBundle,
|
|
40996
41156
|
buildIndustryDiscoveryBundle,
|
|
40997
41157
|
buildMaintenanceAuditBundle,
|
|
40998
41158
|
buildMeetingAnalysisBundle,
|
|
@@ -41007,6 +41167,7 @@ export const collections = {
|
|
|
41007
41167
|
buildResearchPipelineBundle,
|
|
41008
41168
|
buildSoftwareProfileBundle,
|
|
41009
41169
|
buildStandardsResearchBundle,
|
|
41170
|
+
buildTurborepoBundle,
|
|
41010
41171
|
buildUnblockDependentsProcedure,
|
|
41011
41172
|
bundleNameForWorkflowRule,
|
|
41012
41173
|
businessModelsBundle,
|
|
@@ -41124,6 +41285,7 @@ export const collections = {
|
|
|
41124
41285
|
resolveAgentTiers,
|
|
41125
41286
|
resolveAstroProjectOutdir,
|
|
41126
41287
|
resolveAwsCdkProjectOutdir,
|
|
41288
|
+
resolveBuildPolicy,
|
|
41127
41289
|
resolveBundleAgentTiers,
|
|
41128
41290
|
resolveDefaultAgentTier,
|
|
41129
41291
|
resolveIssueDefaults,
|