@codedrifters/configulator 0.0.212 → 0.0.214

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.
@@ -20,9 +20,10 @@ regardless of which specific agent bundles a project enables.
20
20
 
21
21
  Families in this tier:
22
22
 
23
- - **`status:*`** — workflow state (`ready`, `in-progress`, `blocked`,
24
- `done`, `deferred`, `needs-attention`). Required by every agent that
25
- transitions issues through the workflow.
23
+ - **`status:*`** — workflow state (`ready`, `in-progress`,
24
+ `ready-for-review`, `blocked`, `done`, `deferred`,
25
+ `needs-attention`). Required by every agent that transitions issues
26
+ through the workflow.
26
27
  - **`priority:*`** — scheduling priority (`critical`, `high`, `medium`,
27
28
  `low`, `trivial`). Required by the orchestrator to sequence work.
28
29
  - **`type:*`** — conventional-commit work type (`feat`, `fix`, `docs`,
package/lib/index.d.mts CHANGED
@@ -1146,8 +1146,15 @@ declare const requirementsAnalystBundle: AgentRuleBundle;
1146
1146
  declare const researchPipelineBundle: AgentRuleBundle;
1147
1147
 
1148
1148
  /**
1149
- * Slack bundle — opt-in via `includeBundles: ["slack"]`.
1150
- * Never auto-detected (no Slack dependency to introspect).
1149
+ * Slack bundle — auto-activated when the consuming project declares a
1150
+ * Slack integration via `ProjectMetadata.slack`. Consumers can still
1151
+ * opt in manually via `includeBundles: ["slack"]` when they have no
1152
+ * `ProjectMetadata` configured.
1153
+ *
1154
+ * Detection signal: any truthy value on
1155
+ * `ProjectMetadata.of(project).metadata.slack` that carries at least one
1156
+ * channel reference (`projectChannel`, `alertsChannel`, or a non-empty
1157
+ * `channels` record).
1151
1158
  */
1152
1159
  declare const slackBundle: AgentRuleBundle;
1153
1160
 
package/lib/index.d.ts CHANGED
@@ -1195,8 +1195,15 @@ declare const requirementsAnalystBundle: AgentRuleBundle;
1195
1195
  declare const researchPipelineBundle: AgentRuleBundle;
1196
1196
 
1197
1197
  /**
1198
- * Slack bundle — opt-in via `includeBundles: ["slack"]`.
1199
- * Never auto-detected (no Slack dependency to introspect).
1198
+ * Slack bundle — auto-activated when the consuming project declares a
1199
+ * Slack integration via `ProjectMetadata.slack`. Consumers can still
1200
+ * opt in manually via `includeBundles: ["slack"]` when they have no
1201
+ * `ProjectMetadata` configured.
1202
+ *
1203
+ * Detection signal: any truthy value on
1204
+ * `ProjectMetadata.of(project).metadata.slack` that carries at least one
1205
+ * channel reference (`projectChannel`, `alertsChannel`, or a non-empty
1206
+ * `channels` record).
1200
1207
  */
1201
1208
  declare const slackBundle: AgentRuleBundle;
1202
1209
 
package/lib/index.js CHANGED
@@ -792,9 +792,10 @@ var baseBundle = {
792
792
  "|-------|----------|",
793
793
  "| `status:ready` | The issue is fully specified, has no open blockers, and is available for a worker to pick up. |",
794
794
  "| `status:blocked` | The issue cannot be started yet \u2014 either it declares `Depends on: #N` on an open issue, or it is an epic with one or more open children. |",
795
- "| `status:in-progress` | A worker has claimed the issue and a branch exists. Set when the worker starts; cleared only on completion or failure. |",
795
+ "| `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. |",
796
+ "| `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. |",
796
797
  "| `status:needs-attention` | Automated triage has flagged the issue for human review (stale, failed worker, or ambiguous state). Humans reset this label manually. |",
797
- "| `status:done` | The change has shipped. Usually set when the PR merges and the issue closes. |",
798
+ "| `status:done` | The change has shipped. Set when the PR merges and the issue closes. |",
798
799
  "",
799
800
  "### Blocking Rules",
800
801
  "",
@@ -816,9 +817,9 @@ var baseBundle = {
816
817
  " either blocking rule applies.",
817
818
  "- **Worker claims the issue** \u2192 remove `status:ready`, add",
818
819
  " `status:in-progress`. A branch must exist before this transition.",
819
- "- **Worker opens a PR** \u2192 leave `status:in-progress` in place until the",
820
- " PR merges. Do not pre-flip to `status:done`.",
821
- "- **PR merges / issue closes** \u2192 remove `status:in-progress`, add",
820
+ "- **Worker opens a PR** \u2192 remove `status:in-progress`, add",
821
+ " `status:ready-for-review`. The PR URL should be posted on the issue.",
822
+ "- **PR merges / issue closes** \u2192 remove `status:ready-for-review`, add",
822
823
  " `status:done`.",
823
824
  "- **Dependency resolves** \u2192 if the issue was `status:blocked` solely because",
824
825
  " of the dependency-blocking rule, remove `status:blocked` and add",
@@ -835,8 +836,9 @@ var baseBundle = {
835
836
  " by CI. Those are expected self-healing behaviors, not failures.",
836
837
  "",
837
838
  "An issue must always carry exactly one of `status:ready`, `status:blocked`,",
838
- "`status:in-progress`, or `status:done`. The `status:needs-attention` label",
839
- "is additive \u2014 it coexists with whichever of those four applies."
839
+ "`status:in-progress`, `status:ready-for-review`, or `status:done`. The",
840
+ "`status:needs-attention` label is additive \u2014 it coexists with whichever of",
841
+ "those five applies."
840
842
  ].join("\n"),
841
843
  tags: ["workflow"]
842
844
  },
@@ -4358,11 +4360,14 @@ var issueWorkerSubAgent = {
4358
4360
  "",
4359
4361
  "## Phase 8: Update Status",
4360
4362
  "",
4361
- "After the PR is created:",
4363
+ "After the PR is created, transition the issue to the review phase:",
4362
4364
  "```bash",
4363
- 'gh issue edit <number> --remove-label "status:in-progress" --add-label "status:done"',
4365
+ 'gh issue edit <number> --remove-label "status:in-progress" --add-label "status:ready-for-review"',
4364
4366
  "```",
4365
4367
  "",
4368
+ "Do **not** set `status:done` here \u2014 the `pr-reviewer` sub-agent is",
4369
+ "responsible for that transition once the PR successfully merges.",
4370
+ "",
4366
4371
  "## Phase 9: Branch Cleanup",
4367
4372
  "",
4368
4373
  "The PR will not auto-merge until the `pr-reviewer` enables it. Poll the PR",
@@ -5251,6 +5256,14 @@ var prReviewerSubAgent = {
5251
5256
  " git fetch --prune origin",
5252
5257
  " git branch -d <branch-name> 2>/dev/null || git branch -D <branch-name> 2>/dev/null || true",
5253
5258
  " ```",
5259
+ " Transition the linked issue to `status:done` (replaces whichever of",
5260
+ " `status:ready-for-review` or `status:in-progress` it was carrying):",
5261
+ " ```bash",
5262
+ " gh issue edit <issue-number> \\",
5263
+ ' --remove-label "status:ready-for-review" \\',
5264
+ ' --remove-label "status:in-progress" \\',
5265
+ ' --add-label "status:done"',
5266
+ " ```",
5254
5267
  " Then check the linked issue state:",
5255
5268
  " ```bash",
5256
5269
  " gh issue view <issue-number> --json state --jq '.state'",
@@ -6714,11 +6727,106 @@ var researchPipelineBundle = {
6714
6727
  ]
6715
6728
  };
6716
6729
 
6730
+ // src/projects/project-metadata.ts
6731
+ var import_projen2 = require("projen");
6732
+ var import_javascript = require("projen/lib/javascript");
6733
+ var GITHUB_HTTPS_RE = /(?:https?:\/\/|git\+https:\/\/)github\.com\/([^/]+)\/([^/.]+)(?:\.git)?/;
6734
+ var GITHUB_SSH_RE = /git@github\.com:([^/]+)\/([^/.]+)(?:\.git)?/;
6735
+ function parseGitHubUrl(url) {
6736
+ const httpsMatch = url.match(GITHUB_HTTPS_RE);
6737
+ if (httpsMatch) {
6738
+ return { owner: httpsMatch[1], name: httpsMatch[2] };
6739
+ }
6740
+ const sshMatch = url.match(GITHUB_SSH_RE);
6741
+ if (sshMatch) {
6742
+ return { owner: sshMatch[1], name: sshMatch[2] };
6743
+ }
6744
+ return { owner: void 0, name: void 0 };
6745
+ }
6746
+ var ProjectMetadata = class _ProjectMetadata extends import_projen2.Component {
6747
+ /**
6748
+ * Returns the ProjectMetadata instance for a project. Walks up the parent
6749
+ * chain so sub-projects resolve the metadata declared on a root
6750
+ * `MonorepoProject` without needing a duplicate declaration of their own.
6751
+ * Returns `undefined` if no ancestor has a `ProjectMetadata` component.
6752
+ */
6753
+ static of(project) {
6754
+ const isProjectMetadata = (c) => c instanceof _ProjectMetadata;
6755
+ let current = project;
6756
+ while (current) {
6757
+ const found = current.components.find(isProjectMetadata);
6758
+ if (found) {
6759
+ return found;
6760
+ }
6761
+ current = current.parent;
6762
+ }
6763
+ return void 0;
6764
+ }
6765
+ constructor(project, options = {}) {
6766
+ super(project);
6767
+ this.metadata = this.resolveMetadata(options);
6768
+ }
6769
+ /**
6770
+ * Merges explicit options with auto-detected values.
6771
+ * Auto-detection reads the repository URL from package.json
6772
+ * (via Projen's NodePackage manifest) and parses GitHub owner/name.
6773
+ * Explicit options always take precedence over auto-detected values.
6774
+ */
6775
+ resolveMetadata(options) {
6776
+ const autoDetected = this.autoDetectRepository();
6777
+ return {
6778
+ repository: {
6779
+ owner: options.repository?.owner ?? autoDetected.owner,
6780
+ name: options.repository?.name ?? autoDetected.name,
6781
+ defaultBranch: options.repository?.defaultBranch ?? "main"
6782
+ },
6783
+ githubProject: options.githubProject,
6784
+ organization: options.organization,
6785
+ slack: options.slack,
6786
+ labels: options.labels,
6787
+ milestones: options.milestones,
6788
+ docsPath: options.docsPath,
6789
+ deployment: options.deployment
6790
+ };
6791
+ }
6792
+ /**
6793
+ * Attempts to auto-detect repository owner and name from the Projen
6794
+ * project's package.json repository field.
6795
+ */
6796
+ autoDetectRepository() {
6797
+ if (!(this.project instanceof import_javascript.NodeProject)) {
6798
+ return { owner: void 0, name: void 0 };
6799
+ }
6800
+ const manifest = this.project.package.manifest;
6801
+ const repoField = manifest.repository;
6802
+ if (!repoField) {
6803
+ return { owner: void 0, name: void 0 };
6804
+ }
6805
+ const url = typeof repoField === "string" ? repoField : repoField.url ?? "";
6806
+ return parseGitHubUrl(url);
6807
+ }
6808
+ };
6809
+
6717
6810
  // src/agent/bundles/slack.ts
6811
+ function hasSlackConfig(slack) {
6812
+ if (!slack) {
6813
+ return false;
6814
+ }
6815
+ if (slack.projectChannel || slack.alertsChannel) {
6816
+ return true;
6817
+ }
6818
+ if (slack.channels && Object.keys(slack.channels).length > 0) {
6819
+ return true;
6820
+ }
6821
+ return false;
6822
+ }
6718
6823
  var slackBundle = {
6719
6824
  name: "slack",
6720
- description: "Slack MCP message formatting and best practices",
6721
- appliesWhen: () => false,
6825
+ description: "Slack MCP message formatting and best practices. Auto-activates when ProjectMetadata declares a Slack integration; can still be force-included via `includeBundles: ['slack']`.",
6826
+ appliesWhen: (project) => {
6827
+ const pm = ProjectMetadata.of(project);
6828
+ return hasSlackConfig(pm?.metadata.slack);
6829
+ },
6722
6830
  rules: [
6723
6831
  {
6724
6832
  name: "slack-message-formatting",
@@ -6747,7 +6855,11 @@ var slackBundle = {
6747
6855
  " \u2022 Feature B: <https://github.com/org/repo/pull/2|repo#2>",
6748
6856
  " ```",
6749
6857
  "",
6750
- "5. **Avoid:** Plain URLs immediately after a bullet/label on the same line (e.g., `\u2022 Feature A: https://github.com/...`) when sending via API, as it can render with bullets inside or between links"
6858
+ "5. **Avoid:** Plain URLs immediately after a bullet/label on the same line (e.g., `\u2022 Feature A: https://github.com/...`) when sending via API, as it can render with bullets inside or between links",
6859
+ "",
6860
+ "## Activation",
6861
+ "",
6862
+ "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']`."
6751
6863
  ].join("\n"),
6752
6864
  tags: ["workflow"]
6753
6865
  }
@@ -7744,8 +7856,8 @@ var typescriptBundle = {
7744
7856
  };
7745
7857
 
7746
7858
  // src/vitest/vitest-component.ts
7747
- var import_projen2 = require("projen");
7748
- var import_javascript = require("projen/lib/javascript");
7859
+ var import_projen3 = require("projen");
7860
+ var import_javascript2 = require("projen/lib/javascript");
7749
7861
  var import_textfile = require("projen/lib/textfile");
7750
7862
 
7751
7863
  // src/versions.ts
@@ -7823,7 +7935,7 @@ var VERSION = {
7823
7935
  };
7824
7936
 
7825
7937
  // src/vitest/vitest-component.ts
7826
- var Vitest = class _Vitest extends import_projen2.Component {
7938
+ var Vitest = class _Vitest extends import_projen3.Component {
7827
7939
  constructor(project, options = {}) {
7828
7940
  super(project);
7829
7941
  this.project = project;
@@ -7862,7 +7974,7 @@ var Vitest = class _Vitest extends import_projen2.Component {
7862
7974
  preSynthesize() {
7863
7975
  super.preSynthesize();
7864
7976
  for (const component of this.project.components) {
7865
- if (component instanceof import_javascript.Jest) {
7977
+ if (component instanceof import_javascript2.Jest) {
7866
7978
  throw new Error("Vitest cannot be used together with Jest");
7867
7979
  }
7868
7980
  }
@@ -8023,86 +8135,6 @@ function prefix(rel, entry) {
8023
8135
  return path.posix.join(rel, entry);
8024
8136
  }
8025
8137
 
8026
- // src/projects/project-metadata.ts
8027
- var import_projen5 = require("projen");
8028
- var import_javascript2 = require("projen/lib/javascript");
8029
- var GITHUB_HTTPS_RE = /(?:https?:\/\/|git\+https:\/\/)github\.com\/([^/]+)\/([^/.]+)(?:\.git)?/;
8030
- var GITHUB_SSH_RE = /git@github\.com:([^/]+)\/([^/.]+)(?:\.git)?/;
8031
- function parseGitHubUrl(url) {
8032
- const httpsMatch = url.match(GITHUB_HTTPS_RE);
8033
- if (httpsMatch) {
8034
- return { owner: httpsMatch[1], name: httpsMatch[2] };
8035
- }
8036
- const sshMatch = url.match(GITHUB_SSH_RE);
8037
- if (sshMatch) {
8038
- return { owner: sshMatch[1], name: sshMatch[2] };
8039
- }
8040
- return { owner: void 0, name: void 0 };
8041
- }
8042
- var ProjectMetadata = class _ProjectMetadata extends import_projen5.Component {
8043
- /**
8044
- * Returns the ProjectMetadata instance for a project. Walks up the parent
8045
- * chain so sub-projects resolve the metadata declared on a root
8046
- * `MonorepoProject` without needing a duplicate declaration of their own.
8047
- * Returns `undefined` if no ancestor has a `ProjectMetadata` component.
8048
- */
8049
- static of(project) {
8050
- const isProjectMetadata = (c) => c instanceof _ProjectMetadata;
8051
- let current = project;
8052
- while (current) {
8053
- const found = current.components.find(isProjectMetadata);
8054
- if (found) {
8055
- return found;
8056
- }
8057
- current = current.parent;
8058
- }
8059
- return void 0;
8060
- }
8061
- constructor(project, options = {}) {
8062
- super(project);
8063
- this.metadata = this.resolveMetadata(options);
8064
- }
8065
- /**
8066
- * Merges explicit options with auto-detected values.
8067
- * Auto-detection reads the repository URL from package.json
8068
- * (via Projen's NodePackage manifest) and parses GitHub owner/name.
8069
- * Explicit options always take precedence over auto-detected values.
8070
- */
8071
- resolveMetadata(options) {
8072
- const autoDetected = this.autoDetectRepository();
8073
- return {
8074
- repository: {
8075
- owner: options.repository?.owner ?? autoDetected.owner,
8076
- name: options.repository?.name ?? autoDetected.name,
8077
- defaultBranch: options.repository?.defaultBranch ?? "main"
8078
- },
8079
- githubProject: options.githubProject,
8080
- organization: options.organization,
8081
- slack: options.slack,
8082
- labels: options.labels,
8083
- milestones: options.milestones,
8084
- docsPath: options.docsPath,
8085
- deployment: options.deployment
8086
- };
8087
- }
8088
- /**
8089
- * Attempts to auto-detect repository owner and name from the Projen
8090
- * project's package.json repository field.
8091
- */
8092
- autoDetectRepository() {
8093
- if (!(this.project instanceof import_javascript2.NodeProject)) {
8094
- return { owner: void 0, name: void 0 };
8095
- }
8096
- const manifest = this.project.package.manifest;
8097
- const repoField = manifest.repository;
8098
- if (!repoField) {
8099
- return { owner: void 0, name: void 0 };
8100
- }
8101
- const url = typeof repoField === "string" ? repoField : repoField.url ?? "";
8102
- return parseGitHubUrl(url);
8103
- }
8104
- };
8105
-
8106
8138
  // src/agent/renderers/claude-renderer.ts
8107
8139
  var import_projen6 = require("projen");
8108
8140
  var import_textfile2 = require("projen/lib/textfile");
@@ -9889,6 +9921,11 @@ var DEFAULT_STATUS_LABELS = [
9889
9921
  color: "FBCA04",
9890
9922
  description: "Actively being worked on"
9891
9923
  },
9924
+ {
9925
+ name: "status:ready-for-review",
9926
+ color: "1D76DB",
9927
+ description: "PR opened and awaiting review"
9928
+ },
9892
9929
  {
9893
9930
  name: "status:blocked",
9894
9931
  color: "D93F0B",