@codedrifters/configulator 0.0.254 → 0.0.256
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 +260 -1
- package/lib/index.d.ts +261 -2
- package/lib/index.js +193 -0
- package/lib/index.js.map +1 -1
- package/lib/index.mjs +191 -0
- package/lib/index.mjs.map +1 -1
- package/package.json +1 -1
- package/schemas/focus.schema.json +163 -0
package/lib/index.js
CHANGED
|
@@ -243,6 +243,8 @@ __export(index_exports, {
|
|
|
243
243
|
pnpmBundle: () => pnpmBundle,
|
|
244
244
|
prReviewBundle: () => prReviewBundle,
|
|
245
245
|
projenBundle: () => projenBundle,
|
|
246
|
+
renderFocusSection: () => renderFocusSection,
|
|
247
|
+
renderPriorityRulesSection: () => renderPriorityRulesSection,
|
|
246
248
|
requirementsAnalystBundle: () => requirementsAnalystBundle,
|
|
247
249
|
requirementsReviewerBundle: () => requirementsReviewerBundle,
|
|
248
250
|
requirementsWriterBundle: () => requirementsWriterBundle,
|
|
@@ -14580,6 +14582,165 @@ var vitestBundle = {
|
|
|
14580
14582
|
}
|
|
14581
14583
|
};
|
|
14582
14584
|
|
|
14585
|
+
// src/agent/bundles/focus.ts
|
|
14586
|
+
var DEFAULT_FOCUS_FILE_PATH = ".claude/focus.json";
|
|
14587
|
+
var DEFAULT_SCHEMA_VERSION = 1;
|
|
14588
|
+
function renderFocusSection(focus) {
|
|
14589
|
+
if (!focus) {
|
|
14590
|
+
return "";
|
|
14591
|
+
}
|
|
14592
|
+
const focusFilePath = focus.focusFilePath ?? DEFAULT_FOCUS_FILE_PATH;
|
|
14593
|
+
const schemaVersion = focus.schemaVersion ?? DEFAULT_SCHEMA_VERSION;
|
|
14594
|
+
const lines = [
|
|
14595
|
+
"## Focus scoring",
|
|
14596
|
+
"",
|
|
14597
|
+
"This project runs a **focus-scoring engine** alongside the generic",
|
|
14598
|
+
"`priority:*` inference above. Focus scoring boosts the priority of",
|
|
14599
|
+
"issues that match the project's currently-declared focus areas \u2014",
|
|
14600
|
+
"named customers, segments, organizations, software products,",
|
|
14601
|
+
"regulations, or people the project cares about right now.",
|
|
14602
|
+
"",
|
|
14603
|
+
"### Reading `focus.json`",
|
|
14604
|
+
"",
|
|
14605
|
+
`The focus file lives at \`${focusFilePath}\` and conforms to schema`,
|
|
14606
|
+
`version \`${schemaVersion}\`. Each entry declares a match predicate`,
|
|
14607
|
+
"(any combination of `labels`, `titleKeywords`, `bodyKeywords`) and",
|
|
14608
|
+
"a positive integer `weight`. At triage time:",
|
|
14609
|
+
"",
|
|
14610
|
+
`1. Read \`${focusFilePath}\`. If the file is missing or empty,`,
|
|
14611
|
+
" skip focus scoring entirely \u2014 the generic priority heuristics",
|
|
14612
|
+
" apply unchanged.",
|
|
14613
|
+
"2. For each focus area, test its match predicate against the",
|
|
14614
|
+
" issue's labels, title, and body. A match on **any** sub-field",
|
|
14615
|
+
" (labels / title keywords / body keywords) fires the area and",
|
|
14616
|
+
" contributes its `weight` to the issue's focus score.",
|
|
14617
|
+
"3. Keyword matching is case-insensitive substring matching \u2014",
|
|
14618
|
+
' `titleKeywords: ["Acme"]` matches an issue titled',
|
|
14619
|
+
" `feat: onboard acme corp`.",
|
|
14620
|
+
"4. Sum all matched weights to produce the issue's **focus score**.",
|
|
14621
|
+
""
|
|
14622
|
+
];
|
|
14623
|
+
lines.push("### How focus score interacts with `priority:*`");
|
|
14624
|
+
lines.push("");
|
|
14625
|
+
if (focus.thresholds) {
|
|
14626
|
+
const { high, medium } = focus.thresholds;
|
|
14627
|
+
lines.push(`A focus score of \`${high}\` or more boosts the`);
|
|
14628
|
+
const mediumBand = high - medium === 1 ? `A focus score of \`${medium}\` keeps` : `A focus score of \`${medium}\` up to \`${high - 1}\` keeps`;
|
|
14629
|
+
lines.push(
|
|
14630
|
+
"issue to `priority:high`.",
|
|
14631
|
+
`${mediumBand} the issue at \`priority:medium\`. Scores below`,
|
|
14632
|
+
`\`${medium}\` do **not** alter the priority that`,
|
|
14633
|
+
"the generic heuristics would otherwise infer."
|
|
14634
|
+
);
|
|
14635
|
+
} else {
|
|
14636
|
+
lines.push(
|
|
14637
|
+
"This project has not declared explicit focus-score thresholds.",
|
|
14638
|
+
"Treat any non-zero focus score as a soft signal to lift one",
|
|
14639
|
+
"priority tier (never above `priority:high`) unless the generic",
|
|
14640
|
+
"heuristics already pin a higher tier."
|
|
14641
|
+
);
|
|
14642
|
+
}
|
|
14643
|
+
lines.push("");
|
|
14644
|
+
lines.push(
|
|
14645
|
+
"Focus scoring **never lowers** an issue's priority \u2014 the generic",
|
|
14646
|
+
"heuristics set the floor, and focus weight can only lift it.",
|
|
14647
|
+
"`priority:critical` is never set by focus scoring alone; the",
|
|
14648
|
+
"generic heuristics own that tier."
|
|
14649
|
+
);
|
|
14650
|
+
lines.push("");
|
|
14651
|
+
lines.push("### Agent-driven expansion");
|
|
14652
|
+
lines.push("");
|
|
14653
|
+
if (focus.agentExpansionRules) {
|
|
14654
|
+
const rules = focus.agentExpansionRules;
|
|
14655
|
+
const allowedList = rules.allowedTypes.map((t) => `\`${t}\``).join(", ");
|
|
14656
|
+
const forbiddenList = rules.forbiddenTypes.map((t) => `\`${t}\``).join(", ");
|
|
14657
|
+
lines.push(
|
|
14658
|
+
`Agents may **append** new focus areas to \`${focusFilePath}\``,
|
|
14659
|
+
"when they discover a relevant entity during work, subject to",
|
|
14660
|
+
"these guard-rails:"
|
|
14661
|
+
);
|
|
14662
|
+
lines.push("");
|
|
14663
|
+
lines.push(
|
|
14664
|
+
`- **Max weight.** Agent-appended entries must set \`weight\` to`,
|
|
14665
|
+
` \`${rules.maxWeight}\` or less. Higher weights require a human.`
|
|
14666
|
+
);
|
|
14667
|
+
lines.push(
|
|
14668
|
+
"- **Allowed types.** Agents may only introduce entries whose",
|
|
14669
|
+
` \`type\` is one of: ${allowedList || "(none)"}.`
|
|
14670
|
+
);
|
|
14671
|
+
if (rules.forbiddenTypes.length > 0) {
|
|
14672
|
+
lines.push(
|
|
14673
|
+
"- **Forbidden types.** Even inside `allowedTypes`, agents must",
|
|
14674
|
+
` never introduce entries whose \`type\` is one of: ${forbiddenList}.`
|
|
14675
|
+
);
|
|
14676
|
+
}
|
|
14677
|
+
if (rules.maxKeywords !== void 0) {
|
|
14678
|
+
lines.push(
|
|
14679
|
+
"- **Max keywords per match field.** Agent-appended entries",
|
|
14680
|
+
` may list at most \`${rules.maxKeywords}\` items in each of`,
|
|
14681
|
+
" `match.labels`, `match.titleKeywords`, and `match.bodyKeywords`."
|
|
14682
|
+
);
|
|
14683
|
+
}
|
|
14684
|
+
lines.push(
|
|
14685
|
+
'- **Provenance.** Agent-appended entries must set `source: "agent"`',
|
|
14686
|
+
' and `discoveredIn: "#<issue>"` referencing the issue that',
|
|
14687
|
+
" surfaced the focus area."
|
|
14688
|
+
);
|
|
14689
|
+
lines.push(
|
|
14690
|
+
"- **Append-only.** Never modify or remove existing entries.",
|
|
14691
|
+
" Human curators own edits and deletions."
|
|
14692
|
+
);
|
|
14693
|
+
} else {
|
|
14694
|
+
lines.push(
|
|
14695
|
+
`Agents must **not** append to \`${focusFilePath}\`. This project`,
|
|
14696
|
+
"has not declared agent-expansion rules \u2014 all focus-area curation",
|
|
14697
|
+
"is performed by humans. If you discover a relevant entity that",
|
|
14698
|
+
"is not covered by an existing focus area, raise it in the issue",
|
|
14699
|
+
"or PR discussion instead of editing the focus file."
|
|
14700
|
+
);
|
|
14701
|
+
}
|
|
14702
|
+
return lines.join("\n");
|
|
14703
|
+
}
|
|
14704
|
+
|
|
14705
|
+
// src/agent/bundles/priority-rules.ts
|
|
14706
|
+
function renderPriorityRulesSection(rules) {
|
|
14707
|
+
if (rules.length === 0) {
|
|
14708
|
+
return "";
|
|
14709
|
+
}
|
|
14710
|
+
const lines = [
|
|
14711
|
+
"## Project-specific priority rules",
|
|
14712
|
+
"",
|
|
14713
|
+
"These rules are supplied by this project through",
|
|
14714
|
+
"`AgentConfigOptions.priorityRules` and override the generic inference",
|
|
14715
|
+
"heuristics above. Rules evaluate in the order listed; **first match",
|
|
14716
|
+
"wins**. The bundle's default heuristics apply only when no rule below",
|
|
14717
|
+
"matches.",
|
|
14718
|
+
""
|
|
14719
|
+
];
|
|
14720
|
+
rules.forEach((rule, index) => {
|
|
14721
|
+
const matchDetails = [];
|
|
14722
|
+
if (rule.match.labels && rule.match.labels.length > 0) {
|
|
14723
|
+
const labelList = rule.match.labels.map((l) => `\`${l}\``).join(", ");
|
|
14724
|
+
matchDetails.push(`labels: ${labelList}`);
|
|
14725
|
+
}
|
|
14726
|
+
if (rule.match.titleRegex) {
|
|
14727
|
+
matchDetails.push(`title regex: \`${rule.match.titleRegex}\``);
|
|
14728
|
+
}
|
|
14729
|
+
if (rule.match.bodyRegex) {
|
|
14730
|
+
matchDetails.push(`body regex: \`${rule.match.bodyRegex}\``);
|
|
14731
|
+
}
|
|
14732
|
+
if (rule.match.issueNumbers && rule.match.issueNumbers.length > 0) {
|
|
14733
|
+
const numberList = rule.match.issueNumbers.map((n) => `#${n}`).join(", ");
|
|
14734
|
+
matchDetails.push(`issue numbers: ${numberList}`);
|
|
14735
|
+
}
|
|
14736
|
+
const matchSummary = matchDetails.length > 0 ? matchDetails.join("; ") : "(no match fields)";
|
|
14737
|
+
lines.push(
|
|
14738
|
+
`${index + 1}. **\`priority:${rule.priority}\`** when ${matchSummary} \u2014 ${rule.rationale}`
|
|
14739
|
+
);
|
|
14740
|
+
});
|
|
14741
|
+
return lines.join("\n");
|
|
14742
|
+
}
|
|
14743
|
+
|
|
14583
14744
|
// src/agent/bundles/index.ts
|
|
14584
14745
|
var BUILT_IN_BUNDLES = [
|
|
14585
14746
|
baseBundle,
|
|
@@ -15500,6 +15661,36 @@ ${extra}`
|
|
|
15500
15661
|
}
|
|
15501
15662
|
}
|
|
15502
15663
|
}
|
|
15664
|
+
if (this.options.priorityRules && this.options.priorityRules.length > 0) {
|
|
15665
|
+
const issueLabelRule = ruleMap.get("issue-label-conventions");
|
|
15666
|
+
if (issueLabelRule) {
|
|
15667
|
+
const section = renderPriorityRulesSection(this.options.priorityRules);
|
|
15668
|
+
ruleMap.set("issue-label-conventions", {
|
|
15669
|
+
...issueLabelRule,
|
|
15670
|
+
content: `${issueLabelRule.content}
|
|
15671
|
+
|
|
15672
|
+
---
|
|
15673
|
+
|
|
15674
|
+
${section}`
|
|
15675
|
+
});
|
|
15676
|
+
}
|
|
15677
|
+
}
|
|
15678
|
+
if (this.options.focus) {
|
|
15679
|
+
const issueLabelRule = ruleMap.get("issue-label-conventions");
|
|
15680
|
+
if (issueLabelRule) {
|
|
15681
|
+
const section = renderFocusSection(this.options.focus);
|
|
15682
|
+
if (section.length > 0) {
|
|
15683
|
+
ruleMap.set("issue-label-conventions", {
|
|
15684
|
+
...issueLabelRule,
|
|
15685
|
+
content: `${issueLabelRule.content}
|
|
15686
|
+
|
|
15687
|
+
---
|
|
15688
|
+
|
|
15689
|
+
${section}`
|
|
15690
|
+
});
|
|
15691
|
+
}
|
|
15692
|
+
}
|
|
15693
|
+
}
|
|
15503
15694
|
return [...ruleMap.values()].sort((a, b) => {
|
|
15504
15695
|
if (a.name === "project-overview") return -1;
|
|
15505
15696
|
if (b.name === "project-overview") return 1;
|
|
@@ -18311,6 +18502,8 @@ var TypeScriptConfig = class extends import_projen22.Component {
|
|
|
18311
18502
|
pnpmBundle,
|
|
18312
18503
|
prReviewBundle,
|
|
18313
18504
|
projenBundle,
|
|
18505
|
+
renderFocusSection,
|
|
18506
|
+
renderPriorityRulesSection,
|
|
18314
18507
|
requirementsAnalystBundle,
|
|
18315
18508
|
requirementsReviewerBundle,
|
|
18316
18509
|
requirementsWriterBundle,
|