@codedrifters/configulator 0.0.361 → 0.0.363

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.js CHANGED
@@ -451,6 +451,7 @@ __export(index_exports, {
451
451
  renderSkillEvalsRuleContent: () => renderSkillEvalsRuleContent,
452
452
  renderSkillEvalsRunnerScript: () => renderSkillEvalsRunnerScript,
453
453
  renderSourceTierExamples: () => renderSourceTierExamples,
454
+ renderStripToolArtifactTagsProcedure: () => renderStripToolArtifactTagsProcedure,
454
455
  renderTemporalFramingCheckerScript: () => renderTemporalFramingCheckerScript,
455
456
  renderTemporalFramingRuleContent: () => renderTemporalFramingRuleContent,
456
457
  renderUnblockDependentsScript: () => renderUnblockDependentsScript,
@@ -487,6 +488,7 @@ __export(index_exports, {
487
488
  slackBundle: () => slackBundle,
488
489
  softwareProfileBundle: () => softwareProfileBundle,
489
490
  standardsResearchBundle: () => standardsResearchBundle,
491
+ stripToolArtifactTagsProcedure: () => stripToolArtifactTagsProcedure,
490
492
  tsdocRecordToFindings: () => tsdocRecordToFindings,
491
493
  turborepoBundle: () => turborepoBundle,
492
494
  typescriptBundle: () => typescriptBundle,
@@ -4264,7 +4266,7 @@ function buildBaseBundle(paths = DEFAULT_AGENT_PATHS) {
4264
4266
  "- **After modifying Projen configuration**, run the three-step regen sequence: `pnpm i`, then `pnpm exec projen`, then `pnpm i` again. The leading `pnpm i` syncs `node_modules` with the lockfile so synth runs against the right configulator/projen/plugin versions; the trailing `pnpm i` refreshes the lockfile to match anything projen rewrote in `package.json`.",
4265
4267
  "- **Configure dependencies through Projen** \u2014 never use `npm install`, `pnpm add`, or `yarn add`. Add them to `deps` or `devDeps` in Projen config.",
4266
4268
  "- **Export from index.ts** to maintain clean public APIs",
4267
- '- **`defaultMode: "dontAsk"` is configulator\'s hardcoded default** for the rendered Claude Code `settings.json`. Scheduled-task workers (issue-worker, orchestrator, pr-reviewer, and the analyst/writer family) run autonomously and would deadlock on confirmation prompts, so the synthesised default suppresses them. Override only after revisiting the autonomous-worker contract end-to-end; the override path is `claudeSettings.defaultMode` on `AgentConfigOptions`.',
4269
+ '- **`defaultMode` is opt-in** for the rendered Claude Code `settings.json`. configulator does not set it by default, so the synthesised `settings.json` omits the key unless the consumer opts in. Consumers that run autonomous scheduled-task workers (issue-worker, orchestrator, pr-reviewer, and the analyst/writer family) \u2014 which would deadlock on confirmation prompts \u2014 opt in by setting `claudeSettings.defaultMode: "dontAsk"` on `AgentConfigOptions`.',
4268
4270
  "",
4269
4271
  "## Repository Layout",
4270
4272
  "",
@@ -9845,6 +9847,108 @@ var checkLinksProcedure = {
9845
9847
  description: "Link integrity checker that wraps `astro check` (internal links) and `lychee` (external URLs) and normalizes their output into a single JSON-array stream of { url, docPath, line, kind, reason } records. Detection is data: the helper exits 0 when a tool ran successfully regardless of how many broken links it reported. Non-zero exits are reserved for tool-level failures.",
9846
9848
  content: renderCheckLinksProcedure()
9847
9849
  };
9850
+ function renderStripToolArtifactTagsProcedure() {
9851
+ return [
9852
+ "#!/usr/bin/env bash",
9853
+ "# strip-tool-artifact-tags.sh \u2014 remove leaked tool-call wrapper",
9854
+ "# closing tags from the end of an authored markdown file.",
9855
+ "#",
9856
+ "# Usage:",
9857
+ "# .claude/procedures/strip-tool-artifact-tags.sh <file-path>",
9858
+ "#",
9859
+ "# Authoring agents occasionally leak tool-call wrapper *closing*",
9860
+ "# tags (</content>, </invoke>, </parameter>) as trailing whole",
9861
+ "# lines in the markdown they write. astro check and CI link checks",
9862
+ "# do not catch them. This helper strips those EOF artifact lines",
9863
+ "# (plus any now-trailing blank lines) and rewrites the file with a",
9864
+ "# single final newline.",
9865
+ "#",
9866
+ "# Guards (mirrors check-links.sh):",
9867
+ "# - Operates only on an existing file whose path is under",
9868
+ "# docs/src/content/docs/. Any other path, or a missing file,",
9869
+ "# is a silent no-op.",
9870
+ "# - Only WHOLE-LINE EOF tags are removed; inline `<...>` prose or",
9871
+ "# fenced code is never touched.",
9872
+ "# - Idempotent: a re-run on a clean file changes nothing.",
9873
+ "# - Never fails the tool call \u2014 always exits 0. Diagnostics go to",
9874
+ "# stderr only; the file is rewritten only when it changes.",
9875
+ "",
9876
+ "set -uo pipefail",
9877
+ "",
9878
+ "err() {",
9879
+ ' printf "strip-tool-artifact-tags.sh: %s\\n" "$*" >&2',
9880
+ "}",
9881
+ "",
9882
+ "# No file argument: nothing to do.",
9883
+ 'if [ "$#" -lt 1 ]; then',
9884
+ " exit 0",
9885
+ "fi",
9886
+ "",
9887
+ 'file="$1"',
9888
+ "",
9889
+ "# No-op unless the file actually exists and is a regular file.",
9890
+ 'if [ ! -f "$file" ]; then',
9891
+ " exit 0",
9892
+ "fi",
9893
+ "",
9894
+ "# Path guard: only touch markdown under the Starlight content tree.",
9895
+ "# Match the canonical content-root segment anywhere in the path so",
9896
+ "# the guard works for both absolute and repo-relative paths.",
9897
+ 'case "$file" in',
9898
+ " *docs/src/content/docs/*) ;;",
9899
+ " *) exit 0 ;;",
9900
+ "esac",
9901
+ "",
9902
+ "# Rewrite the file with trailing artifact tags and trailing blank",
9903
+ "# lines removed. awk buffers every line, then walks back from EOF",
9904
+ "# dropping lines that are blank or exactly one of the leaked",
9905
+ "# closing tags (trailing whitespace tolerated). Whatever survives",
9906
+ "# is re-emitted with a single final newline. Only whole lines are",
9907
+ "# considered, so inline `<...>` content is never altered.",
9908
+ 'tmp_out="$(mktemp -t strip-tool-artifact-tags-XXXXXX)" || exit 0',
9909
+ "# shellcheck disable=SC2064",
9910
+ `trap "rm -f '$tmp_out'" EXIT`,
9911
+ "",
9912
+ "awk '",
9913
+ " { lines[NR] = $0 }",
9914
+ " END {",
9915
+ " last = NR",
9916
+ " while (last > 0) {",
9917
+ " line = lines[last]",
9918
+ " # Strip trailing whitespace (spaces, tabs, CR) for the match.",
9919
+ " stripped = line",
9920
+ ' sub(/[ \\t\\r]+$/, "", stripped)',
9921
+ ' if (stripped == "" \\',
9922
+ ' || stripped == "</content>" \\',
9923
+ ' || stripped == "</invoke>" \\',
9924
+ ' || stripped == "</parameter>") {',
9925
+ " last--",
9926
+ " continue",
9927
+ " }",
9928
+ " break",
9929
+ " }",
9930
+ " for (i = 1; i <= last; i++) {",
9931
+ " print lines[i]",
9932
+ " }",
9933
+ " }",
9934
+ `' "$file" > "$tmp_out" || exit 0`,
9935
+ "",
9936
+ "# Only write back when the content actually changed \u2014 keeps the",
9937
+ "# helper a true no-op on clean files (idempotent re-runs included).",
9938
+ 'if ! cmp -s "$tmp_out" "$file"; then',
9939
+ ' if ! cat "$tmp_out" > "$file"; then',
9940
+ ' err "failed to rewrite $file"',
9941
+ " fi",
9942
+ "fi",
9943
+ "",
9944
+ "exit 0"
9945
+ ].join("\n");
9946
+ }
9947
+ var stripToolArtifactTagsProcedure = {
9948
+ name: "strip-tool-artifact-tags.sh",
9949
+ description: "Strips leaked tool-call wrapper closing tags (</content>, </invoke>, </parameter>) that authoring agents occasionally emit as trailing whole lines in markdown, plus any now-trailing blank lines, leaving a single final newline. Operates only on an existing file under docs/src/content/docs/; idempotent, a no-op on clean or missing files, and always exits 0 so it can never fail a PostToolUse hook.",
9950
+ content: renderStripToolArtifactTagsProcedure()
9951
+ };
9848
9952
  function renderCheckDocSamplesProcedure() {
9849
9953
  const nodeScript = [
9850
9954
  "(async () => {",
@@ -10017,7 +10121,8 @@ function buildDocsSyncBundle(paths = DEFAULT_AGENT_PATHS) {
10017
10121
  procedures: [
10018
10122
  extractApiProcedure,
10019
10123
  checkLinksProcedure,
10020
- checkDocSamplesProcedure
10124
+ checkDocSamplesProcedure,
10125
+ stripToolArtifactTagsProcedure
10021
10126
  ],
10022
10127
  labels: [
10023
10128
  {
@@ -12643,6 +12748,36 @@ function buildMeetingAnalystSubAgent(tier) {
12643
12748
  "**Goal:** Create GitHub issues for follow-up work, cross-reference the",
12644
12749
  "meeting into existing documentation, and complete bi-directional traceability.",
12645
12750
  "",
12751
+ "### Idempotent dedup gate (open AND closed)",
12752
+ "",
12753
+ "Phase 3 (`meeting:draft`) already files one downstream issue per",
12754
+ "drafted artifact \u2014 a `req:write` per requirement draft, plus",
12755
+ "`docs:write` / `bcm:*` / `research:scope` where applicable. Phase 4",
12756
+ "must **not** re-file what Phase 3 already filed. Before creating",
12757
+ "**any** downstream issue (`req:write`, `docs:write`, `bcm:*`,",
12758
+ "`research:scope`) for a drafted artifact, dedup against existing",
12759
+ "issues:",
12760
+ "",
12761
+ "1. **Search open AND closed issues** for one already covering the",
12762
+ " same artifact, matching on the draft's title / basename \u2014 e.g.",
12763
+ " `gh issue list --search '<draft title or basename>' --state all --json number,title,state`.",
12764
+ " Searching **all states** is load-bearing: the original may have",
12765
+ " already been worked and **merged (closed)**, and an open-only",
12766
+ " search misses it \u2014 re-filing then collides with the shipped",
12767
+ " document and produces an ID-collision PR.",
12768
+ "2. **If a match exists (open or closed), SKIP creation.** Link to",
12769
+ " the existing issue from the `## Downstream Artifacts` section",
12770
+ " instead of filing a new one.",
12771
+ "3. **Only create issues for follow-up work that has no Phase 3",
12772
+ " draft.** A drafted artifact already has its downstream issue;",
12773
+ " file new issues only for items the draft phase did not cover.",
12774
+ "4. **Be idempotent.** Re-running the same `meeting:link` issue must",
12775
+ " file nothing new \u2014 a second run finds the first run's issues",
12776
+ " (now open or closed) via the same search and skips them.",
12777
+ "",
12778
+ "Apply this gate to **both** Step 2 (requirement issues) and Step 4",
12779
+ "(action-item routing) below.",
12780
+ "",
12646
12781
  "### Steps",
12647
12782
  "",
12648
12783
  "1. Read the drafts from Phase 3 (if they exist) and the extraction",
@@ -12652,6 +12787,11 @@ function buildMeetingAnalystSubAgent(tier) {
12652
12787
  " are in scope for direct edits on this meeting. Apply the rules in",
12653
12788
  " the **Areas filtering** section above.",
12654
12789
  "2. Create requirement issues using `gh issue create` with appropriate labels.",
12790
+ " **First apply the Idempotent dedup gate above:** search open AND",
12791
+ " closed issues for one already covering the drafted requirement",
12792
+ " (match on its title / basename) and **skip creation when a match",
12793
+ " exists** \u2014 Phase 3 already filed a `req:write` issue per requirement",
12794
+ " draft, so file here only for requirements with no Phase 3 draft.",
12655
12795
  " Include a `## Traceability` section in each issue body linking back to",
12656
12796
  " the source meeting and extraction file. Issue creation is **not**",
12657
12797
  " gated by areas.",
@@ -12666,9 +12806,13 @@ function buildMeetingAnalystSubAgent(tier) {
12666
12806
  " \u2014 a `req:write` issue for a requirement, a `docs:write` issue",
12667
12807
  " for a docs page, `bcm:*` for a capability model, a",
12668
12808
  " `research:scope` issue for a research note, or a roadmap /",
12669
- " product-doc follow-up. Use the matching template from the",
12670
- " issue-templates page; include a `## Traceability` section.",
12671
- " Issue creation is not gated by areas.",
12809
+ " product-doc follow-up. **First apply the Idempotent dedup gate",
12810
+ " above:** search open AND closed issues for one already covering",
12811
+ " this artifact and **skip creation when a match exists** (link",
12812
+ " to it instead) \u2014 file only for action items that have no Phase",
12813
+ " 3 draft. Use the matching template from the issue-templates",
12814
+ " page; include a `## Traceability` section. Issue creation is",
12815
+ " not gated by areas.",
12672
12816
  " - **Human-owned** (send/schedule/install/decide/communicate/",
12673
12817
  " get-access/build-elsewhere): record it **only** in the notes",
12674
12818
  " `## Action Items` table (step 8 already carries the table",
@@ -14044,7 +14188,7 @@ var DEFAULT_BUNDLE_OVERRIDES = {
14044
14188
  acceptanceCriteria: { smallMax: 3, mediumMax: 14 }
14045
14189
  },
14046
14190
  "regulatory:research": {
14047
- acceptanceCriteria: { smallMax: 3, mediumMax: 10 }
14191
+ acceptanceCriteria: { smallMax: 3, mediumMax: 12 }
14048
14192
  },
14049
14193
  "standards:research": {
14050
14194
  acceptanceCriteria: { smallMax: 3, mediumMax: 10 }
@@ -14060,6 +14204,32 @@ var DEFAULT_BUNDLE_OVERRIDES = {
14060
14204
  "software:matrix": {
14061
14205
  acceptanceCriteria: { smallMax: 3, mediumMax: 12 },
14062
14206
  sources: { smallMax: 2, mediumMax: 15 }
14207
+ },
14208
+ "people:research": {
14209
+ acceptanceCriteria: { smallMax: 3, mediumMax: 12 }
14210
+ },
14211
+ "company:research": {
14212
+ acceptanceCriteria: { smallMax: 3, mediumMax: 12 }
14213
+ },
14214
+ "people:draft": {
14215
+ acceptanceCriteria: { smallMax: 3, mediumMax: 12 }
14216
+ },
14217
+ "company:draft": {
14218
+ acceptanceCriteria: { smallMax: 3, mediumMax: 12 }
14219
+ },
14220
+ "req:draft-trace": {
14221
+ acceptanceCriteria: { smallMax: 3, mediumMax: 20 }
14222
+ },
14223
+ "meeting:notes": {
14224
+ acceptanceCriteria: { smallMax: 3, mediumMax: 9 }
14225
+ },
14226
+ "meeting:draft": {
14227
+ acceptanceCriteria: { smallMax: 3, mediumMax: 15 },
14228
+ sources: { smallMax: 2, mediumMax: 10 }
14229
+ },
14230
+ "meeting:link": {
14231
+ acceptanceCriteria: { smallMax: 3, mediumMax: 15 },
14232
+ sources: { smallMax: 2, mediumMax: 10 }
14063
14233
  }
14064
14234
  };
14065
14235
  var DEFAULT_DECOMPOSITION_TEMPLATE = [
@@ -14323,17 +14493,30 @@ function renderScopeGateShellHelpers(gate) {
14323
14493
  " body=$(cat)",
14324
14494
  " local ac_count sources_count",
14325
14495
  ` ac_count=$(printf '%s\\n' "$body" | awk '`,
14326
- " BEGIN { in_ac=0; count=0 }",
14496
+ " # Count only TOP-LEVEL checkboxes \u2014 those at the shallowest",
14497
+ " # indentation in each Acceptance-Criteria section. A checkbox",
14498
+ " # with nested/indented sub-checkboxes (e.g. a `file N action-",
14499
+ " # item issues` criterion) counts once, mirroring the TS",
14500
+ " # countTopLevelCheckboxes() helper.",
14501
+ " function flush() {",
14502
+ " if (n > 0) { for (i = 0; i < n; i++) if (indents[i] == mini) total++ }",
14503
+ " n = 0; mini = -1",
14504
+ " }",
14505
+ " BEGIN { in_ac=0; total=0; n=0; mini=-1 }",
14327
14506
  " # Fully case-insensitive heading match mirrors the TypeScript",
14328
14507
  " # classifier (/^## acceptance criteria\\s*$/i); POSIX awk has",
14329
14508
  " # no /i flag, so we compare via tolower() instead of a",
14330
14509
  " # per-letter character class like [Aa]cceptance [Cc]riteria",
14331
14510
  " # which would drift for headings like `## ACCEPTANCE CRITERIA`.",
14332
14511
  " { lower = tolower($0) }",
14333
- " lower ~ /^## acceptance criteria[[:space:]]*$/ { in_ac=1; next }",
14334
- " /^## / { in_ac=0 }",
14335
- " in_ac && /^[[:space:]]*-[[:space:]]*\\[[ xX]\\]/ { count++ }",
14336
- " END { print count }",
14512
+ " lower ~ /^## acceptance criteria[[:space:]]*$/ { flush(); in_ac=1; next }",
14513
+ " /^## / { if (in_ac) { flush(); in_ac=0 } }",
14514
+ " in_ac && /^[[:space:]]*-[[:space:]]*\\[[ xX]\\]/ {",
14515
+ " match($0, /^[[:space:]]*/); ind = RLENGTH;",
14516
+ " indents[n++] = ind;",
14517
+ " if (mini < 0 || ind < mini) mini = ind;",
14518
+ " }",
14519
+ " END { flush(); print total }",
14337
14520
  " ')",
14338
14521
  ` sources_count=$(printf '%s\\n' "$body" | awk '`,
14339
14522
  " BEGIN { in_src=0; count=0 }",
@@ -14342,7 +14525,16 @@ function renderScopeGateShellHelpers(gate) {
14342
14525
  " { lower = tolower($0) }",
14343
14526
  " lower ~ /^## (inputs|references|sources)[[:space:]]*$/ { in_src=1; next }",
14344
14527
  " /^## / { in_src=0 }",
14345
- " in_src && /^[[:space:]]*[-*][[:space:]]+/ { count++ }",
14528
+ " # Exclude `Key: value` metadata bullets (e.g. `- Basename: \u2026`)",
14529
+ " # \u2014 a bullet whose text is a `Word:` key/value pair is",
14530
+ " # metadata, not a source. Mirrors the TS countSourceBullets()",
14531
+ " # METADATA_KEY_VALUE_REGEX exclusion.",
14532
+ " in_src && /^[[:space:]]*[-*][[:space:]]+/ {",
14533
+ " rest = $0;",
14534
+ ' sub(/^[[:space:]]*[-*][[:space:]]+/, "", rest);',
14535
+ " if (rest ~ /^[A-Za-z][A-Za-z0-9-]*:[[:space:]]+[^[:space:]]/) next;",
14536
+ " count++;",
14537
+ " }",
14346
14538
  " END { print count }",
14347
14539
  " ')",
14348
14540
  ` printf 'ac=%s sources=%s\\n' "$ac_count" "$sources_count" >&2`,
@@ -14497,37 +14689,80 @@ function resolveScopeClass(acCount, sourcesCount, thresholds) {
14497
14689
  }
14498
14690
  return "large";
14499
14691
  }
14692
+ var AC_CHECKBOX_REGEX = /^(\s*)-\s*\[[ xX]\]/;
14693
+ var SOURCES_BULLET_REGEX = /^\s*[-*]\s+(.*)$/;
14694
+ var METADATA_KEY_VALUE_REGEX = /^[A-Za-z][A-Za-z0-9-]*:\s+\S/;
14500
14695
  function countAcceptanceCriteria(body) {
14501
14696
  return countSectionMatches(
14502
14697
  body,
14503
14698
  /^## acceptance criteria\s*$/i,
14504
- /^\s*-\s*\[[ xX]\]/
14699
+ countTopLevelCheckboxes
14505
14700
  );
14506
14701
  }
14507
14702
  function countSources(body) {
14508
14703
  return countSectionMatches(
14509
14704
  body,
14510
14705
  /^## (?:inputs|references|sources)\s*$/i,
14511
- /^\s*[-*]\s+/
14706
+ countSourceBullets
14512
14707
  );
14513
14708
  }
14514
- function countSectionMatches(body, headingRegex, lineRegex) {
14709
+ function countTopLevelCheckboxes(sectionLines) {
14710
+ let minIndent = Infinity;
14711
+ const indents = [];
14712
+ for (const line of sectionLines) {
14713
+ const match = AC_CHECKBOX_REGEX.exec(line);
14714
+ if (match === null) {
14715
+ continue;
14716
+ }
14717
+ const indent = match[1].length;
14718
+ indents.push(indent);
14719
+ if (indent < minIndent) {
14720
+ minIndent = indent;
14721
+ }
14722
+ }
14723
+ return indents.filter((indent) => indent === minIndent).length;
14724
+ }
14725
+ function countSourceBullets(sectionLines) {
14726
+ let count = 0;
14727
+ for (const line of sectionLines) {
14728
+ const match = SOURCES_BULLET_REGEX.exec(line);
14729
+ if (match === null) {
14730
+ continue;
14731
+ }
14732
+ if (METADATA_KEY_VALUE_REGEX.test(match[1])) {
14733
+ continue;
14734
+ }
14735
+ count += 1;
14736
+ }
14737
+ return count;
14738
+ }
14739
+ function countSectionMatches(body, headingRegex, lineCounter) {
14515
14740
  const lines = body.split(/\r?\n/);
14516
14741
  let count = 0;
14517
14742
  let inSection = false;
14743
+ let sectionLines = [];
14744
+ const flush = () => {
14745
+ if (sectionLines.length > 0) {
14746
+ count += lineCounter(sectionLines);
14747
+ sectionLines = [];
14748
+ }
14749
+ };
14518
14750
  for (const line of lines) {
14519
14751
  if (headingRegex.test(line)) {
14752
+ flush();
14520
14753
  inSection = true;
14521
14754
  continue;
14522
14755
  }
14523
14756
  if (inSection && /^## /.test(line)) {
14757
+ flush();
14524
14758
  inSection = false;
14525
14759
  continue;
14526
14760
  }
14527
- if (inSection && lineRegex.test(line)) {
14528
- count += 1;
14761
+ if (inSection) {
14762
+ sectionLines.push(line);
14529
14763
  }
14530
14764
  }
14765
+ flush();
14531
14766
  return count;
14532
14767
  }
14533
14768
 
@@ -30996,7 +31231,7 @@ var VERSION = {
30996
31231
  /**
30997
31232
  * Version of Projen to use.
30998
31233
  */
30999
- PROJEN_VERSION: "0.99.80",
31234
+ PROJEN_VERSION: "0.100.2",
31000
31235
  /**
31001
31236
  * Version of `actions/setup-node` to use in GitHub workflows.
31002
31237
  * Tracks the version projen currently emits (see node_modules/projen/lib/github/workflows.js).
@@ -32716,7 +32951,7 @@ var DEFAULT_CLAUDE_HOOKS = {
32716
32951
  hooks: [
32717
32952
  {
32718
32953
  type: "command",
32719
- command: 'case "${CLAUDE_TOOL_INPUT_path:-}" in *docs/src/content/docs/*) if [ -x .claude/procedures/check-links.sh ]; then bash .claude/procedures/check-links.sh "$CLAUDE_TOOL_INPUT_path" 2>&1 | head -20; fi ;; esac'
32954
+ command: 'case "${CLAUDE_TOOL_INPUT_path:-}" in *docs/src/content/docs/*) if [ -x .claude/procedures/strip-tool-artifact-tags.sh ]; then bash .claude/procedures/strip-tool-artifact-tags.sh "$CLAUDE_TOOL_INPUT_path" >/dev/null 2>&1; fi; if [ -x .claude/procedures/check-links.sh ]; then bash .claude/procedures/check-links.sh "$CLAUDE_TOOL_INPUT_path" 2>&1 | head -20; fi ;; esac'
32720
32955
  }
32721
32956
  ]
32722
32957
  }
@@ -32805,8 +33040,10 @@ var AgentConfig = class _AgentConfig extends import_projen8.Component {
32805
33040
  * `Array.from(new Set(...))`; V8 `Set` iteration preserves insertion
32806
33041
  * order, so the final ordering is defaults first, then bundle, then
32807
33042
  * user, with duplicates removed (first-occurrence wins). `defaultMode`
32808
- * defaults to `"dontAsk"` unless overridden see the inline comment
32809
- * on the literal below for the autonomous-worker rationale.
33043
+ * is opt-in (steering decision D7): it is set only from
33044
+ * `userSettings.defaultMode` and left undefined otherwise, so the
33045
+ * renderer omits the key for un-opted-in consumers — see the inline
33046
+ * comment on the literal below.
32810
33047
  *
32811
33048
  * Hooks merge: consumer-supplied entries first, then default entries
32812
33049
  * (Stop, PostToolUse), deduped by `(matcher, JSON-serialized hooks)`.
@@ -32829,15 +33066,16 @@ var AgentConfig = class _AgentConfig extends import_projen8.Component {
32829
33066
  const userDeny = userSettings?.permissions?.deny ?? [];
32830
33067
  return {
32831
33068
  ...userSettings,
32832
- // `defaultMode: "dontAsk"` is configulator's hardcoded default
32833
- // because scheduled-task workers (issue-worker, orchestrator,
32834
- // pr-reviewer, and the analyst/writer family) run autonomously
32835
- // and would deadlock on confirmation prompts. Any other value
32836
- // breaks the autonomous-worker contract override only after
32837
- // revisiting that contract end-to-end. The override path for
32838
- // consumers is `claudeSettings.defaultMode` on
32839
- // `AgentConfigOptions`.
32840
- defaultMode: userSettings?.defaultMode ?? "dontAsk",
33069
+ // `defaultMode` is opt-in (steering decision D7): the base
33070
+ // output does NOT set it unless the consumer supplies
33071
+ // `claudeSettings.defaultMode`. When it is undefined the renderer
33072
+ // omits the key entirely, so an un-opted-in consumer's rendered
33073
+ // settings carry no `defaultMode`. Consumers that run autonomous
33074
+ // scheduled-task workers (issue-worker, orchestrator, pr-reviewer,
33075
+ // and the analyst/writer family) — which would deadlock on
33076
+ // confirmation prompts — opt in by setting
33077
+ // `claudeSettings.defaultMode: "dontAsk"`.
33078
+ defaultMode: userSettings?.defaultMode,
32841
33079
  permissions: {
32842
33080
  ...userSettings?.permissions,
32843
33081
  allow: Array.from(
@@ -36645,7 +36883,7 @@ export default preview;
36645
36883
  }
36646
36884
 
36647
36885
  // src/projects/astro-project.ts
36648
- var import_projen25 = require("projen");
36886
+ var import_projen24 = require("projen");
36649
36887
  var import_ts_deepmerge3 = require("ts-deepmerge");
36650
36888
 
36651
36889
  // src/projects/monorepo-layout.ts
@@ -36793,13 +37031,12 @@ function resolveReactViteSiteProjectOutdir(packageName) {
36793
37031
  }
36794
37032
 
36795
37033
  // src/projects/typescript-project.ts
36796
- var import_projen24 = require("projen");
37034
+ var import_projen23 = require("projen");
36797
37035
  var import_javascript4 = require("projen/lib/javascript");
36798
37036
  var import_release = require("projen/lib/release");
36799
37037
  var import_ts_deepmerge2 = require("ts-deepmerge");
36800
37038
 
36801
37039
  // src/projects/monorepo-project.ts
36802
- var import_projen21 = require("projen");
36803
37040
  var import_github5 = require("projen/lib/github");
36804
37041
  var import_javascript3 = require("projen/lib/javascript");
36805
37042
  var import_typescript3 = require("projen/lib/typescript");
@@ -37842,11 +38079,17 @@ var MonorepoProject = class extends import_typescript3.TypeScriptAppProject {
37842
38079
  * rewritten workspace — matching the canonical regen sequence consumers
37843
38080
  * already document (`pnpm i && pnpm exec projen && pnpm i`, neither frozen).
37844
38081
  *
38082
+ * Runs the task via `this.tasks.runTask` (the public task-execution API,
38083
+ * which projen itself uses in `NodePackage.installDependencies`) rather than
38084
+ * constructing a `TaskRuntime`: projen 0.100 removed `TaskRuntime` from the
38085
+ * package root and made it internal to the CLI. `Tasks.runTask` is stable
38086
+ * across the 0.99/0.100 boundary and executes against this project's outdir,
38087
+ * so behavior is unchanged.
38088
+ *
37845
38089
  * @see https://github.com/codedrifters/packages/issues/570
37846
38090
  */
37847
38091
  installDependenciesNonFrozen() {
37848
- const runtime = new import_projen21.TaskRuntime(this.outdir);
37849
- runtime.runTask(this.package.installTask.name);
38092
+ this.tasks.runTask(this.package.installTask.name);
37850
38093
  }
37851
38094
  /**
37852
38095
  * Hooks into the install dependencies cycle
@@ -37867,11 +38110,11 @@ var MonorepoProject = class extends import_typescript3.TypeScriptAppProject {
37867
38110
  };
37868
38111
 
37869
38112
  // src/typescript/tsdoc-config.ts
37870
- var import_projen22 = require("projen");
38113
+ var import_projen21 = require("projen");
37871
38114
  var STANDARD_MODIFIER_TAGS = ["@default"];
37872
38115
  var STANDARD_INLINE_TAGS = ["@code"];
37873
38116
  var ALWAYS_ON_SCOPES = ["@codedrifters"];
37874
- var TsdocConfig = class _TsdocConfig extends import_projen22.Component {
38117
+ var TsdocConfig = class _TsdocConfig extends import_projen21.Component {
37875
38118
  /**
37876
38119
  * Derive a workspace scope from a scoped package name (`@scope/name`).
37877
38120
  * Returns `undefined` when the name is unscoped.
@@ -37916,7 +38159,7 @@ var TsdocConfig = class _TsdocConfig extends import_projen22.Component {
37916
38159
  allowMultiple: true
37917
38160
  }))
37918
38161
  ].sort((a, b) => a.tagName.localeCompare(b.tagName));
37919
- new import_projen22.JsonFile(project, "tsdoc.json", {
38162
+ new import_projen21.JsonFile(project, "tsdoc.json", {
37920
38163
  marker: false,
37921
38164
  obj: {
37922
38165
  $schema: "https://developer.microsoft.com/json-schemas/tsdoc/v0/tsdoc.schema.json",
@@ -37929,9 +38172,9 @@ var TsdocConfig = class _TsdocConfig extends import_projen22.Component {
37929
38172
 
37930
38173
  // src/typescript/typescript-config.ts
37931
38174
  var import_node_path3 = require("path");
37932
- var import_projen23 = require("projen");
38175
+ var import_projen22 = require("projen");
37933
38176
  var import_path = require("projen/lib/util/path");
37934
- var TypeScriptConfig = class extends import_projen23.Component {
38177
+ var TypeScriptConfig = class extends import_projen22.Component {
37935
38178
  constructor(project) {
37936
38179
  super(project);
37937
38180
  let tsPaths = {};
@@ -37962,7 +38205,7 @@ var TestRunner = {
37962
38205
  JEST: "jest",
37963
38206
  VITEST: "vitest"
37964
38207
  };
37965
- var TypeScriptProject = class extends import_projen24.typescript.TypeScriptProject {
38208
+ var TypeScriptProject = class extends import_projen23.typescript.TypeScriptProject {
37966
38209
  constructor(userOptions) {
37967
38210
  if (!(userOptions.parent instanceof MonorepoProject)) {
37968
38211
  throw new Error(
@@ -38284,10 +38527,10 @@ var AstroProject = class extends TypeScriptProject {
38284
38527
  adapter: options.adapter
38285
38528
  });
38286
38529
  if (options.sampleCode === true) {
38287
- new import_projen25.SampleFile(this, "src/pages/index.astro", {
38530
+ new import_projen24.SampleFile(this, "src/pages/index.astro", {
38288
38531
  contents: DEFAULT_INDEX_ASTRO
38289
38532
  });
38290
- new import_projen25.SampleFile(this, "public/favicon.svg", {
38533
+ new import_projen24.SampleFile(this, "public/favicon.svg", {
38291
38534
  contents: DEFAULT_FAVICON_SVG
38292
38535
  });
38293
38536
  }
@@ -38312,19 +38555,19 @@ var DEFAULT_FAVICON_SVG = `<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0
38312
38555
  `;
38313
38556
 
38314
38557
  // src/projects/aws-cdk-project.ts
38315
- var import_projen28 = require("projen");
38558
+ var import_projen27 = require("projen");
38316
38559
  var import_javascript5 = require("projen/lib/javascript");
38317
38560
  var import_release2 = require("projen/lib/release");
38318
38561
  var import_ts_deepmerge4 = require("ts-deepmerge");
38319
38562
 
38320
38563
  // src/workflows/aws-deploy-workflow.ts
38321
38564
  var import_utils11 = __toESM(require_lib());
38322
- var import_projen26 = require("projen");
38565
+ var import_projen25 = require("projen");
38323
38566
  var import_build = require("projen/lib/build");
38324
38567
  var import_github6 = require("projen/lib/github");
38325
38568
  var import_workflows_model5 = require("projen/lib/github/workflows-model");
38326
38569
  var PROD_DEPLOY_NAME = "prod-deploy";
38327
- var AwsDeployWorkflow = class _AwsDeployWorkflow extends import_projen26.Component {
38570
+ var AwsDeployWorkflow = class _AwsDeployWorkflow extends import_projen25.Component {
38328
38571
  constructor(project, options = {}) {
38329
38572
  super(project);
38330
38573
  this.project = project;
@@ -38641,7 +38884,7 @@ var AwsDeployWorkflow = class _AwsDeployWorkflow extends import_projen26.Compone
38641
38884
  };
38642
38885
 
38643
38886
  // src/workflows/aws-teardown-workflow.ts
38644
- var import_projen27 = require("projen");
38887
+ var import_projen26 = require("projen");
38645
38888
  var import_github7 = require("projen/lib/github");
38646
38889
  var import_workflows_model6 = require("projen/lib/github/workflows-model");
38647
38890
  var DEFAULT_TEARDOWN_BRANCH_PATTERNS = [
@@ -38663,7 +38906,7 @@ var resolveBranchPatterns = (explicit, targets) => {
38663
38906
  }
38664
38907
  return [...DEFAULT_TEARDOWN_BRANCH_PATTERNS];
38665
38908
  };
38666
- var AwsTeardownWorkflow = class extends import_projen27.Component {
38909
+ var AwsTeardownWorkflow = class extends import_projen26.Component {
38667
38910
  constructor(rootProject, options) {
38668
38911
  super(rootProject);
38669
38912
  this.rootProject = rootProject;
@@ -38845,7 +39088,7 @@ var AwsTeardownWorkflow = class extends import_projen27.Component {
38845
39088
  };
38846
39089
 
38847
39090
  // src/projects/aws-cdk-project.ts
38848
- var AwsCdkProject = class extends import_projen28.awscdk.AwsCdkTypeScriptApp {
39091
+ var AwsCdkProject = class extends import_projen27.awscdk.AwsCdkTypeScriptApp {
38849
39092
  constructor(userOptions) {
38850
39093
  if (!(userOptions.parent instanceof MonorepoProject)) {
38851
39094
  throw new Error(
@@ -39042,7 +39285,7 @@ var AwsCdkProject = class extends import_projen28.awscdk.AwsCdkTypeScriptApp {
39042
39285
  };
39043
39286
 
39044
39287
  // src/projects/react-vite-site-project.ts
39045
- var import_projen29 = require("projen");
39288
+ var import_projen28 = require("projen");
39046
39289
  var import_ts_deepmerge5 = require("ts-deepmerge");
39047
39290
  var ReactViteSiteProject = class extends TypeScriptProject {
39048
39291
  constructor(userOptions) {
@@ -39052,12 +39295,12 @@ var ReactViteSiteProject = class extends TypeScriptProject {
39052
39295
  const defaultOptions = {
39053
39296
  testRunner: TestRunner.VITEST,
39054
39297
  apiExtractor: false,
39055
- // ESLint inherited from TypeScriptProject lints `src` by default;
39056
- // skip projen's `.projenrc.ts` lint pass since downstream sites
39057
- // configure projen through their own root project.
39298
+ // ESLint inherited from TypeScriptProject lints `src` only. projen 0.100
39299
+ // removed the `lintProjenRc` option and no longer auto-lints the projenrc
39300
+ // file, so the previous explicit opt-out is unnecessary — downstream
39301
+ // sites configure projen through their own root project.
39058
39302
  eslintOptions: {
39059
- dirs: ["src"],
39060
- lintProjenRc: false
39303
+ dirs: ["src"]
39061
39304
  },
39062
39305
  // VSCode workspace defaults (Prettier formatter, ESLint on save)
39063
39306
  // need a project-level `.vscode/` folder. The inherited
@@ -39081,7 +39324,7 @@ var ReactViteSiteProject = class extends TypeScriptProject {
39081
39324
  };
39082
39325
  super(options);
39083
39326
  this.package.addField("type", "module");
39084
- new import_projen29.TextFile(this, ".nvmrc", { lines: ["v24.11.0"] });
39327
+ new import_projen28.TextFile(this, ".nvmrc", { lines: ["v24.11.0"] });
39085
39328
  this.tsconfig?.file.addOverride("compilerOptions.target", "ES2020");
39086
39329
  this.tsconfig?.file.addOverride("compilerOptions.lib", [
39087
39330
  "ES2020",
@@ -39131,7 +39374,7 @@ var ReactViteSiteProject = class extends TypeScriptProject {
39131
39374
  "build",
39132
39375
  ".turbo"
39133
39376
  ]);
39134
- new import_projen29.SampleFile(this, "vite.config.ts", {
39377
+ new import_projen28.SampleFile(this, "vite.config.ts", {
39135
39378
  contents: `import { defineConfig } from 'vite';
39136
39379
  import react from '@vitejs/plugin-react';
39137
39380
  import tailwindcss from '@tailwindcss/vite';
@@ -39143,7 +39386,7 @@ export default defineConfig({
39143
39386
  });
39144
39387
  `
39145
39388
  });
39146
- new import_projen29.SampleFile(this, "src/vite-env.d.ts", {
39389
+ new import_projen28.SampleFile(this, "src/vite-env.d.ts", {
39147
39390
  contents: `/// <reference types="vite/client" />
39148
39391
 
39149
39392
  interface ImportMetaEnv {
@@ -39158,7 +39401,7 @@ interface ImportMeta {
39158
39401
  });
39159
39402
  if (options.testRunner !== TestRunner.JEST) {
39160
39403
  this.tryRemoveFile("vitest.config.ts");
39161
- new import_projen29.SampleFile(this, "vitest.config.ts", {
39404
+ new import_projen28.SampleFile(this, "vitest.config.ts", {
39162
39405
  contents: `import { defineConfig, mergeConfig } from 'vitest/config';
39163
39406
  import react from '@vitejs/plugin-react';
39164
39407
  import viteConfig from './vite.config';
@@ -39302,7 +39545,7 @@ export default mergeConfig(
39302
39545
  }
39303
39546
  if (userOptions.sampleCode === true) {
39304
39547
  const siteName = options.name;
39305
- new import_projen29.SampleFile(this, "index.html", {
39548
+ new import_projen28.SampleFile(this, "index.html", {
39306
39549
  contents: `<!doctype html>
39307
39550
  <html>
39308
39551
  <head>
@@ -39317,7 +39560,7 @@ export default mergeConfig(
39317
39560
  </html>
39318
39561
  `
39319
39562
  });
39320
- new import_projen29.SampleFile(this, "src/routes.tsx", {
39563
+ new import_projen28.SampleFile(this, "src/routes.tsx", {
39321
39564
  contents: `import { createBrowserRouter } from 'react-router-dom';
39322
39565
  import App from './App';
39323
39566
 
@@ -39326,7 +39569,7 @@ export const router = createBrowserRouter([
39326
39569
  ]);
39327
39570
  `
39328
39571
  });
39329
- new import_projen29.SampleFile(this, "src/main.tsx", {
39572
+ new import_projen28.SampleFile(this, "src/main.tsx", {
39330
39573
  contents: `import React from 'react';
39331
39574
  import ReactDOM from 'react-dom/client';
39332
39575
  import { RouterProvider } from 'react-router-dom';
@@ -39340,7 +39583,7 @@ ReactDOM.createRoot(document.getElementById('root')!).render(
39340
39583
  );
39341
39584
  `
39342
39585
  });
39343
- new import_projen29.SampleFile(this, "src/App.tsx", {
39586
+ new import_projen28.SampleFile(this, "src/App.tsx", {
39344
39587
  contents: `export default function App() {
39345
39588
  return (
39346
39589
  <main className="p-4">
@@ -39350,11 +39593,11 @@ ReactDOM.createRoot(document.getElementById('root')!).render(
39350
39593
  }
39351
39594
  `
39352
39595
  });
39353
- new import_projen29.SampleFile(this, "src/index.css", {
39596
+ new import_projen28.SampleFile(this, "src/index.css", {
39354
39597
  contents: `@import "tailwindcss";
39355
39598
  `
39356
39599
  });
39357
- new import_projen29.SampleFile(this, "src/setupTests.ts", {
39600
+ new import_projen28.SampleFile(this, "src/setupTests.ts", {
39358
39601
  contents: `import '@testing-library/jest-dom';
39359
39602
  `
39360
39603
  });
@@ -39363,7 +39606,7 @@ ReactDOM.createRoot(document.getElementById('root')!).render(
39363
39606
  };
39364
39607
 
39365
39608
  // src/projects/starlight-project.ts
39366
- var import_projen30 = require("projen");
39609
+ var import_projen29 = require("projen");
39367
39610
  var STARLIGHT_ROLE = {
39368
39611
  DOCS: "docs",
39369
39612
  SITE: "site"
@@ -39405,10 +39648,10 @@ var StarlightProject = class extends AstroProject {
39405
39648
  turbo.compileTask.inputs.push("src/content/**");
39406
39649
  }
39407
39650
  if (userOptions.sampleContent === true) {
39408
- new import_projen30.SampleFile(this, "src/content/docs/index.mdx", {
39651
+ new import_projen29.SampleFile(this, "src/content/docs/index.mdx", {
39409
39652
  contents: DEFAULT_INDEX_MDX
39410
39653
  });
39411
- new import_projen30.SampleFile(this, "src/content.config.ts", {
39654
+ new import_projen29.SampleFile(this, "src/content.config.ts", {
39412
39655
  contents: DEFAULT_CONTENT_CONFIG_TS
39413
39656
  });
39414
39657
  }
@@ -39758,6 +40001,7 @@ export const collections = {
39758
40001
  renderSkillEvalsRuleContent,
39759
40002
  renderSkillEvalsRunnerScript,
39760
40003
  renderSourceTierExamples,
40004
+ renderStripToolArtifactTagsProcedure,
39761
40005
  renderTemporalFramingCheckerScript,
39762
40006
  renderTemporalFramingRuleContent,
39763
40007
  renderUnblockDependentsScript,
@@ -39794,6 +40038,7 @@ export const collections = {
39794
40038
  slackBundle,
39795
40039
  softwareProfileBundle,
39796
40040
  standardsResearchBundle,
40041
+ stripToolArtifactTagsProcedure,
39797
40042
  tsdocRecordToFindings,
39798
40043
  turborepoBundle,
39799
40044
  typescriptBundle,