@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 +38 -2
- package/lib/index.d.ts +38 -2
- package/lib/index.js +120 -87
- package/lib/index.js.map +1 -1
- package/lib/index.mjs +122 -89
- package/lib/index.mjs.map +1 -1
- package/package.json +1 -1
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 —
|
|
1150
|
-
*
|
|
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 —
|
|
1199
|
-
*
|
|
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: () =>
|
|
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
|
|
7761
|
-
var
|
|
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
|
|
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
|
|
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) {
|