@codedrifters/configulator 0.0.213 → 0.0.215

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 CHANGED
@@ -198,9 +198,38 @@ interface AgentSkill {
198
198
  readonly paths?: ReadonlyArray<string>;
199
199
  /**
200
200
  * Resource directories bundled with the skill (e.g., references/, scripts/, assets/).
201
+ * Documentation hint only — directory names listed here are not emitted to disk.
202
+ * Prefer {@link referenceFiles} to ship actual companion file contents.
203
+ *
204
+ * @deprecated Use {@link referenceFiles} to emit physical companion files.
201
205
  * @example ['references/', 'scripts/']
202
206
  */
203
207
  readonly references?: ReadonlyArray<string>;
208
+ /**
209
+ * Companion files shipped alongside the SKILL.md (e.g., templates, references, scripts).
210
+ * Each entry is rendered as a TextFile under the skill's directory on every
211
+ * platform that emits skills (Claude: `.claude/skills/{name}/{path}`,
212
+ * Cursor: `.cursor/skills/{name}/{path}`).
213
+ *
214
+ * Use this for skill assets that benefit from being separate files rather than
215
+ * inlined into the skill instructions — large templates, reference tables,
216
+ * runnable scripts.
217
+ *
218
+ * Per-platform `platforms.{claude,cursor}.exclude` flags suppress reference
219
+ * files for that platform alongside the SKILL.md.
220
+ *
221
+ * @example
222
+ * referenceFiles: [
223
+ * { path: '_references/templates/_template-FR.md', content: '# Functional Requirement\n...' },
224
+ * { path: '_references/standards-and-frameworks.md', content: '# Standards\n...' },
225
+ * ]
226
+ */
227
+ readonly referenceFiles?: ReadonlyArray<{
228
+ /** Path relative to the skill directory (e.g., `_references/templates/_template-FR.md`). */
229
+ readonly path: string;
230
+ /** File contents written verbatim. */
231
+ readonly content: string;
232
+ }>;
204
233
  /**
205
234
  * Context isolation mode. Set to 'fork' to run in an isolated subagent context.
206
235
  */
@@ -1146,8 +1175,15 @@ declare const requirementsAnalystBundle: AgentRuleBundle;
1146
1175
  declare const researchPipelineBundle: AgentRuleBundle;
1147
1176
 
1148
1177
  /**
1149
- * Slack bundle — opt-in via `includeBundles: ["slack"]`.
1150
- * Never auto-detected (no Slack dependency to introspect).
1178
+ * Slack bundle — auto-activated when the consuming project declares a
1179
+ * Slack integration via `ProjectMetadata.slack`. Consumers can still
1180
+ * opt in manually via `includeBundles: ["slack"]` when they have no
1181
+ * `ProjectMetadata` configured.
1182
+ *
1183
+ * Detection signal: any truthy value on
1184
+ * `ProjectMetadata.of(project).metadata.slack` that carries at least one
1185
+ * channel reference (`projectChannel`, `alertsChannel`, or a non-empty
1186
+ * `channels` record).
1151
1187
  */
1152
1188
  declare const slackBundle: AgentRuleBundle;
1153
1189
 
package/lib/index.d.ts CHANGED
@@ -247,9 +247,38 @@ interface AgentSkill {
247
247
  readonly paths?: ReadonlyArray<string>;
248
248
  /**
249
249
  * Resource directories bundled with the skill (e.g., references/, scripts/, assets/).
250
+ * Documentation hint only — directory names listed here are not emitted to disk.
251
+ * Prefer {@link referenceFiles} to ship actual companion file contents.
252
+ *
253
+ * @deprecated Use {@link referenceFiles} to emit physical companion files.
250
254
  * @example ['references/', 'scripts/']
251
255
  */
252
256
  readonly references?: ReadonlyArray<string>;
257
+ /**
258
+ * Companion files shipped alongside the SKILL.md (e.g., templates, references, scripts).
259
+ * Each entry is rendered as a TextFile under the skill's directory on every
260
+ * platform that emits skills (Claude: `.claude/skills/{name}/{path}`,
261
+ * Cursor: `.cursor/skills/{name}/{path}`).
262
+ *
263
+ * Use this for skill assets that benefit from being separate files rather than
264
+ * inlined into the skill instructions — large templates, reference tables,
265
+ * runnable scripts.
266
+ *
267
+ * Per-platform `platforms.{claude,cursor}.exclude` flags suppress reference
268
+ * files for that platform alongside the SKILL.md.
269
+ *
270
+ * @example
271
+ * referenceFiles: [
272
+ * { path: '_references/templates/_template-FR.md', content: '# Functional Requirement\n...' },
273
+ * { path: '_references/standards-and-frameworks.md', content: '# Standards\n...' },
274
+ * ]
275
+ */
276
+ readonly referenceFiles?: ReadonlyArray<{
277
+ /** Path relative to the skill directory (e.g., `_references/templates/_template-FR.md`). */
278
+ readonly path: string;
279
+ /** File contents written verbatim. */
280
+ readonly content: string;
281
+ }>;
253
282
  /**
254
283
  * Context isolation mode. Set to 'fork' to run in an isolated subagent context.
255
284
  */
@@ -1195,8 +1224,15 @@ declare const requirementsAnalystBundle: AgentRuleBundle;
1195
1224
  declare const researchPipelineBundle: AgentRuleBundle;
1196
1225
 
1197
1226
  /**
1198
- * Slack bundle — opt-in via `includeBundles: ["slack"]`.
1199
- * Never auto-detected (no Slack dependency to introspect).
1227
+ * Slack bundle — auto-activated when the consuming project declares a
1228
+ * Slack integration via `ProjectMetadata.slack`. Consumers can still
1229
+ * opt in manually via `includeBundles: ["slack"]` when they have no
1230
+ * `ProjectMetadata` configured.
1231
+ *
1232
+ * Detection signal: any truthy value on
1233
+ * `ProjectMetadata.of(project).metadata.slack` that carries at least one
1234
+ * channel reference (`projectChannel`, `alertsChannel`, or a non-empty
1235
+ * `channels` record).
1200
1236
  */
1201
1237
  declare const slackBundle: AgentRuleBundle;
1202
1238
 
package/lib/index.js CHANGED
@@ -6727,11 +6727,106 @@ var researchPipelineBundle = {
6727
6727
  ]
6728
6728
  };
6729
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
+
6730
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
+ }
6731
6823
  var slackBundle = {
6732
6824
  name: "slack",
6733
- description: "Slack MCP message formatting and best practices",
6734
- 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
+ },
6735
6830
  rules: [
6736
6831
  {
6737
6832
  name: "slack-message-formatting",
@@ -6760,7 +6855,11 @@ var slackBundle = {
6760
6855
  " \u2022 Feature B: <https://github.com/org/repo/pull/2|repo#2>",
6761
6856
  " ```",
6762
6857
  "",
6763
- "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']`."
6764
6863
  ].join("\n"),
6765
6864
  tags: ["workflow"]
6766
6865
  }
@@ -7757,8 +7856,8 @@ var typescriptBundle = {
7757
7856
  };
7758
7857
 
7759
7858
  // src/vitest/vitest-component.ts
7760
- var import_projen2 = require("projen");
7761
- var import_javascript = require("projen/lib/javascript");
7859
+ var import_projen3 = require("projen");
7860
+ var import_javascript2 = require("projen/lib/javascript");
7762
7861
  var import_textfile = require("projen/lib/textfile");
7763
7862
 
7764
7863
  // src/versions.ts
@@ -7836,7 +7935,7 @@ var VERSION = {
7836
7935
  };
7837
7936
 
7838
7937
  // src/vitest/vitest-component.ts
7839
- var Vitest = class _Vitest extends import_projen2.Component {
7938
+ var Vitest = class _Vitest extends import_projen3.Component {
7840
7939
  constructor(project, options = {}) {
7841
7940
  super(project);
7842
7941
  this.project = project;
@@ -7875,7 +7974,7 @@ var Vitest = class _Vitest extends import_projen2.Component {
7875
7974
  preSynthesize() {
7876
7975
  super.preSynthesize();
7877
7976
  for (const component of this.project.components) {
7878
- if (component instanceof import_javascript.Jest) {
7977
+ if (component instanceof import_javascript2.Jest) {
7879
7978
  throw new Error("Vitest cannot be used together with Jest");
7880
7979
  }
7881
7980
  }
@@ -8036,86 +8135,6 @@ function prefix(rel, entry) {
8036
8135
  return path.posix.join(rel, entry);
8037
8136
  }
8038
8137
 
8039
- // src/projects/project-metadata.ts
8040
- var import_projen5 = require("projen");
8041
- var import_javascript2 = require("projen/lib/javascript");
8042
- var GITHUB_HTTPS_RE = /(?:https?:\/\/|git\+https:\/\/)github\.com\/([^/]+)\/([^/.]+)(?:\.git)?/;
8043
- var GITHUB_SSH_RE = /git@github\.com:([^/]+)\/([^/.]+)(?:\.git)?/;
8044
- function parseGitHubUrl(url) {
8045
- const httpsMatch = url.match(GITHUB_HTTPS_RE);
8046
- if (httpsMatch) {
8047
- return { owner: httpsMatch[1], name: httpsMatch[2] };
8048
- }
8049
- const sshMatch = url.match(GITHUB_SSH_RE);
8050
- if (sshMatch) {
8051
- return { owner: sshMatch[1], name: sshMatch[2] };
8052
- }
8053
- return { owner: void 0, name: void 0 };
8054
- }
8055
- var ProjectMetadata = class _ProjectMetadata extends import_projen5.Component {
8056
- /**
8057
- * Returns the ProjectMetadata instance for a project. Walks up the parent
8058
- * chain so sub-projects resolve the metadata declared on a root
8059
- * `MonorepoProject` without needing a duplicate declaration of their own.
8060
- * Returns `undefined` if no ancestor has a `ProjectMetadata` component.
8061
- */
8062
- static of(project) {
8063
- const isProjectMetadata = (c) => c instanceof _ProjectMetadata;
8064
- let current = project;
8065
- while (current) {
8066
- const found = current.components.find(isProjectMetadata);
8067
- if (found) {
8068
- return found;
8069
- }
8070
- current = current.parent;
8071
- }
8072
- return void 0;
8073
- }
8074
- constructor(project, options = {}) {
8075
- super(project);
8076
- this.metadata = this.resolveMetadata(options);
8077
- }
8078
- /**
8079
- * Merges explicit options with auto-detected values.
8080
- * Auto-detection reads the repository URL from package.json
8081
- * (via Projen's NodePackage manifest) and parses GitHub owner/name.
8082
- * Explicit options always take precedence over auto-detected values.
8083
- */
8084
- resolveMetadata(options) {
8085
- const autoDetected = this.autoDetectRepository();
8086
- return {
8087
- repository: {
8088
- owner: options.repository?.owner ?? autoDetected.owner,
8089
- name: options.repository?.name ?? autoDetected.name,
8090
- defaultBranch: options.repository?.defaultBranch ?? "main"
8091
- },
8092
- githubProject: options.githubProject,
8093
- organization: options.organization,
8094
- slack: options.slack,
8095
- labels: options.labels,
8096
- milestones: options.milestones,
8097
- docsPath: options.docsPath,
8098
- deployment: options.deployment
8099
- };
8100
- }
8101
- /**
8102
- * Attempts to auto-detect repository owner and name from the Projen
8103
- * project's package.json repository field.
8104
- */
8105
- autoDetectRepository() {
8106
- if (!(this.project instanceof import_javascript2.NodeProject)) {
8107
- return { owner: void 0, name: void 0 };
8108
- }
8109
- const manifest = this.project.package.manifest;
8110
- const repoField = manifest.repository;
8111
- if (!repoField) {
8112
- return { owner: void 0, name: void 0 };
8113
- }
8114
- const url = typeof repoField === "string" ? repoField : repoField.url ?? "";
8115
- return parseGitHubUrl(url);
8116
- }
8117
- };
8118
-
8119
8138
  // src/agent/renderers/claude-renderer.ts
8120
8139
  var import_projen6 = require("projen");
8121
8140
  var import_textfile2 = require("projen/lib/textfile");
@@ -8381,6 +8400,13 @@ var ClaudeRenderer = class _ClaudeRenderer {
8381
8400
  new import_textfile2.TextFile(component, `.claude/skills/${skill.name}/SKILL.md`, {
8382
8401
  lines
8383
8402
  });
8403
+ if (skill.referenceFiles && skill.referenceFiles.length > 0) {
8404
+ for (const file of skill.referenceFiles) {
8405
+ new import_textfile2.TextFile(component, `.claude/skills/${skill.name}/${file.path}`, {
8406
+ lines: file.content.split("\n")
8407
+ });
8408
+ }
8409
+ }
8384
8410
  }
8385
8411
  }
8386
8412
  static renderSubAgents(component, subAgents) {
@@ -8552,6 +8578,13 @@ var CursorRenderer = class _CursorRenderer {
8552
8578
  new import_textfile3.TextFile(component, `.cursor/skills/${skill.name}/SKILL.md`, {
8553
8579
  lines
8554
8580
  });
8581
+ if (skill.referenceFiles && skill.referenceFiles.length > 0) {
8582
+ for (const file of skill.referenceFiles) {
8583
+ new import_textfile3.TextFile(component, `.cursor/skills/${skill.name}/${file.path}`, {
8584
+ lines: file.content.split("\n")
8585
+ });
8586
+ }
8587
+ }
8555
8588
  }
8556
8589
  }
8557
8590
  static renderSubAgents(component, subAgents) {