@codedrifters/configulator 0.0.361 → 0.0.362

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.mjs CHANGED
@@ -3927,7 +3927,7 @@ function buildBaseBundle(paths = DEFAULT_AGENT_PATHS) {
3927
3927
  "- **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`.",
3928
3928
  "- **Configure dependencies through Projen** \u2014 never use `npm install`, `pnpm add`, or `yarn add`. Add them to `deps` or `devDeps` in Projen config.",
3929
3929
  "- **Export from index.ts** to maintain clean public APIs",
3930
- '- **`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`.',
3930
+ '- **`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`.',
3931
3931
  "",
3932
3932
  "## Repository Layout",
3933
3933
  "",
@@ -9508,6 +9508,108 @@ var checkLinksProcedure = {
9508
9508
  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.",
9509
9509
  content: renderCheckLinksProcedure()
9510
9510
  };
9511
+ function renderStripToolArtifactTagsProcedure() {
9512
+ return [
9513
+ "#!/usr/bin/env bash",
9514
+ "# strip-tool-artifact-tags.sh \u2014 remove leaked tool-call wrapper",
9515
+ "# closing tags from the end of an authored markdown file.",
9516
+ "#",
9517
+ "# Usage:",
9518
+ "# .claude/procedures/strip-tool-artifact-tags.sh <file-path>",
9519
+ "#",
9520
+ "# Authoring agents occasionally leak tool-call wrapper *closing*",
9521
+ "# tags (</content>, </invoke>, </parameter>) as trailing whole",
9522
+ "# lines in the markdown they write. astro check and CI link checks",
9523
+ "# do not catch them. This helper strips those EOF artifact lines",
9524
+ "# (plus any now-trailing blank lines) and rewrites the file with a",
9525
+ "# single final newline.",
9526
+ "#",
9527
+ "# Guards (mirrors check-links.sh):",
9528
+ "# - Operates only on an existing file whose path is under",
9529
+ "# docs/src/content/docs/. Any other path, or a missing file,",
9530
+ "# is a silent no-op.",
9531
+ "# - Only WHOLE-LINE EOF tags are removed; inline `<...>` prose or",
9532
+ "# fenced code is never touched.",
9533
+ "# - Idempotent: a re-run on a clean file changes nothing.",
9534
+ "# - Never fails the tool call \u2014 always exits 0. Diagnostics go to",
9535
+ "# stderr only; the file is rewritten only when it changes.",
9536
+ "",
9537
+ "set -uo pipefail",
9538
+ "",
9539
+ "err() {",
9540
+ ' printf "strip-tool-artifact-tags.sh: %s\\n" "$*" >&2',
9541
+ "}",
9542
+ "",
9543
+ "# No file argument: nothing to do.",
9544
+ 'if [ "$#" -lt 1 ]; then',
9545
+ " exit 0",
9546
+ "fi",
9547
+ "",
9548
+ 'file="$1"',
9549
+ "",
9550
+ "# No-op unless the file actually exists and is a regular file.",
9551
+ 'if [ ! -f "$file" ]; then',
9552
+ " exit 0",
9553
+ "fi",
9554
+ "",
9555
+ "# Path guard: only touch markdown under the Starlight content tree.",
9556
+ "# Match the canonical content-root segment anywhere in the path so",
9557
+ "# the guard works for both absolute and repo-relative paths.",
9558
+ 'case "$file" in',
9559
+ " *docs/src/content/docs/*) ;;",
9560
+ " *) exit 0 ;;",
9561
+ "esac",
9562
+ "",
9563
+ "# Rewrite the file with trailing artifact tags and trailing blank",
9564
+ "# lines removed. awk buffers every line, then walks back from EOF",
9565
+ "# dropping lines that are blank or exactly one of the leaked",
9566
+ "# closing tags (trailing whitespace tolerated). Whatever survives",
9567
+ "# is re-emitted with a single final newline. Only whole lines are",
9568
+ "# considered, so inline `<...>` content is never altered.",
9569
+ 'tmp_out="$(mktemp -t strip-tool-artifact-tags-XXXXXX)" || exit 0',
9570
+ "# shellcheck disable=SC2064",
9571
+ `trap "rm -f '$tmp_out'" EXIT`,
9572
+ "",
9573
+ "awk '",
9574
+ " { lines[NR] = $0 }",
9575
+ " END {",
9576
+ " last = NR",
9577
+ " while (last > 0) {",
9578
+ " line = lines[last]",
9579
+ " # Strip trailing whitespace (spaces, tabs, CR) for the match.",
9580
+ " stripped = line",
9581
+ ' sub(/[ \\t\\r]+$/, "", stripped)',
9582
+ ' if (stripped == "" \\',
9583
+ ' || stripped == "</content>" \\',
9584
+ ' || stripped == "</invoke>" \\',
9585
+ ' || stripped == "</parameter>") {',
9586
+ " last--",
9587
+ " continue",
9588
+ " }",
9589
+ " break",
9590
+ " }",
9591
+ " for (i = 1; i <= last; i++) {",
9592
+ " print lines[i]",
9593
+ " }",
9594
+ " }",
9595
+ `' "$file" > "$tmp_out" || exit 0`,
9596
+ "",
9597
+ "# Only write back when the content actually changed \u2014 keeps the",
9598
+ "# helper a true no-op on clean files (idempotent re-runs included).",
9599
+ 'if ! cmp -s "$tmp_out" "$file"; then',
9600
+ ' if ! cat "$tmp_out" > "$file"; then',
9601
+ ' err "failed to rewrite $file"',
9602
+ " fi",
9603
+ "fi",
9604
+ "",
9605
+ "exit 0"
9606
+ ].join("\n");
9607
+ }
9608
+ var stripToolArtifactTagsProcedure = {
9609
+ name: "strip-tool-artifact-tags.sh",
9610
+ 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.",
9611
+ content: renderStripToolArtifactTagsProcedure()
9612
+ };
9511
9613
  function renderCheckDocSamplesProcedure() {
9512
9614
  const nodeScript = [
9513
9615
  "(async () => {",
@@ -9680,7 +9782,8 @@ function buildDocsSyncBundle(paths = DEFAULT_AGENT_PATHS) {
9680
9782
  procedures: [
9681
9783
  extractApiProcedure,
9682
9784
  checkLinksProcedure,
9683
- checkDocSamplesProcedure
9785
+ checkDocSamplesProcedure,
9786
+ stripToolArtifactTagsProcedure
9684
9787
  ],
9685
9788
  labels: [
9686
9789
  {
@@ -12306,6 +12409,36 @@ function buildMeetingAnalystSubAgent(tier) {
12306
12409
  "**Goal:** Create GitHub issues for follow-up work, cross-reference the",
12307
12410
  "meeting into existing documentation, and complete bi-directional traceability.",
12308
12411
  "",
12412
+ "### Idempotent dedup gate (open AND closed)",
12413
+ "",
12414
+ "Phase 3 (`meeting:draft`) already files one downstream issue per",
12415
+ "drafted artifact \u2014 a `req:write` per requirement draft, plus",
12416
+ "`docs:write` / `bcm:*` / `research:scope` where applicable. Phase 4",
12417
+ "must **not** re-file what Phase 3 already filed. Before creating",
12418
+ "**any** downstream issue (`req:write`, `docs:write`, `bcm:*`,",
12419
+ "`research:scope`) for a drafted artifact, dedup against existing",
12420
+ "issues:",
12421
+ "",
12422
+ "1. **Search open AND closed issues** for one already covering the",
12423
+ " same artifact, matching on the draft's title / basename \u2014 e.g.",
12424
+ " `gh issue list --search '<draft title or basename>' --state all --json number,title,state`.",
12425
+ " Searching **all states** is load-bearing: the original may have",
12426
+ " already been worked and **merged (closed)**, and an open-only",
12427
+ " search misses it \u2014 re-filing then collides with the shipped",
12428
+ " document and produces an ID-collision PR.",
12429
+ "2. **If a match exists (open or closed), SKIP creation.** Link to",
12430
+ " the existing issue from the `## Downstream Artifacts` section",
12431
+ " instead of filing a new one.",
12432
+ "3. **Only create issues for follow-up work that has no Phase 3",
12433
+ " draft.** A drafted artifact already has its downstream issue;",
12434
+ " file new issues only for items the draft phase did not cover.",
12435
+ "4. **Be idempotent.** Re-running the same `meeting:link` issue must",
12436
+ " file nothing new \u2014 a second run finds the first run's issues",
12437
+ " (now open or closed) via the same search and skips them.",
12438
+ "",
12439
+ "Apply this gate to **both** Step 2 (requirement issues) and Step 4",
12440
+ "(action-item routing) below.",
12441
+ "",
12309
12442
  "### Steps",
12310
12443
  "",
12311
12444
  "1. Read the drafts from Phase 3 (if they exist) and the extraction",
@@ -12315,6 +12448,11 @@ function buildMeetingAnalystSubAgent(tier) {
12315
12448
  " are in scope for direct edits on this meeting. Apply the rules in",
12316
12449
  " the **Areas filtering** section above.",
12317
12450
  "2. Create requirement issues using `gh issue create` with appropriate labels.",
12451
+ " **First apply the Idempotent dedup gate above:** search open AND",
12452
+ " closed issues for one already covering the drafted requirement",
12453
+ " (match on its title / basename) and **skip creation when a match",
12454
+ " exists** \u2014 Phase 3 already filed a `req:write` issue per requirement",
12455
+ " draft, so file here only for requirements with no Phase 3 draft.",
12318
12456
  " Include a `## Traceability` section in each issue body linking back to",
12319
12457
  " the source meeting and extraction file. Issue creation is **not**",
12320
12458
  " gated by areas.",
@@ -12329,9 +12467,13 @@ function buildMeetingAnalystSubAgent(tier) {
12329
12467
  " \u2014 a `req:write` issue for a requirement, a `docs:write` issue",
12330
12468
  " for a docs page, `bcm:*` for a capability model, a",
12331
12469
  " `research:scope` issue for a research note, or a roadmap /",
12332
- " product-doc follow-up. Use the matching template from the",
12333
- " issue-templates page; include a `## Traceability` section.",
12334
- " Issue creation is not gated by areas.",
12470
+ " product-doc follow-up. **First apply the Idempotent dedup gate",
12471
+ " above:** search open AND closed issues for one already covering",
12472
+ " this artifact and **skip creation when a match exists** (link",
12473
+ " to it instead) \u2014 file only for action items that have no Phase",
12474
+ " 3 draft. Use the matching template from the issue-templates",
12475
+ " page; include a `## Traceability` section. Issue creation is",
12476
+ " not gated by areas.",
12335
12477
  " - **Human-owned** (send/schedule/install/decide/communicate/",
12336
12478
  " get-access/build-elsewhere): record it **only** in the notes",
12337
12479
  " `## Action Items` table (step 8 already carries the table",
@@ -13707,7 +13849,7 @@ var DEFAULT_BUNDLE_OVERRIDES = {
13707
13849
  acceptanceCriteria: { smallMax: 3, mediumMax: 14 }
13708
13850
  },
13709
13851
  "regulatory:research": {
13710
- acceptanceCriteria: { smallMax: 3, mediumMax: 10 }
13852
+ acceptanceCriteria: { smallMax: 3, mediumMax: 12 }
13711
13853
  },
13712
13854
  "standards:research": {
13713
13855
  acceptanceCriteria: { smallMax: 3, mediumMax: 10 }
@@ -13723,6 +13865,32 @@ var DEFAULT_BUNDLE_OVERRIDES = {
13723
13865
  "software:matrix": {
13724
13866
  acceptanceCriteria: { smallMax: 3, mediumMax: 12 },
13725
13867
  sources: { smallMax: 2, mediumMax: 15 }
13868
+ },
13869
+ "people:research": {
13870
+ acceptanceCriteria: { smallMax: 3, mediumMax: 12 }
13871
+ },
13872
+ "company:research": {
13873
+ acceptanceCriteria: { smallMax: 3, mediumMax: 12 }
13874
+ },
13875
+ "people:draft": {
13876
+ acceptanceCriteria: { smallMax: 3, mediumMax: 12 }
13877
+ },
13878
+ "company:draft": {
13879
+ acceptanceCriteria: { smallMax: 3, mediumMax: 12 }
13880
+ },
13881
+ "req:draft-trace": {
13882
+ acceptanceCriteria: { smallMax: 3, mediumMax: 20 }
13883
+ },
13884
+ "meeting:notes": {
13885
+ acceptanceCriteria: { smallMax: 3, mediumMax: 9 }
13886
+ },
13887
+ "meeting:draft": {
13888
+ acceptanceCriteria: { smallMax: 3, mediumMax: 15 },
13889
+ sources: { smallMax: 2, mediumMax: 10 }
13890
+ },
13891
+ "meeting:link": {
13892
+ acceptanceCriteria: { smallMax: 3, mediumMax: 15 },
13893
+ sources: { smallMax: 2, mediumMax: 10 }
13726
13894
  }
13727
13895
  };
13728
13896
  var DEFAULT_DECOMPOSITION_TEMPLATE = [
@@ -13986,17 +14154,30 @@ function renderScopeGateShellHelpers(gate) {
13986
14154
  " body=$(cat)",
13987
14155
  " local ac_count sources_count",
13988
14156
  ` ac_count=$(printf '%s\\n' "$body" | awk '`,
13989
- " BEGIN { in_ac=0; count=0 }",
14157
+ " # Count only TOP-LEVEL checkboxes \u2014 those at the shallowest",
14158
+ " # indentation in each Acceptance-Criteria section. A checkbox",
14159
+ " # with nested/indented sub-checkboxes (e.g. a `file N action-",
14160
+ " # item issues` criterion) counts once, mirroring the TS",
14161
+ " # countTopLevelCheckboxes() helper.",
14162
+ " function flush() {",
14163
+ " if (n > 0) { for (i = 0; i < n; i++) if (indents[i] == mini) total++ }",
14164
+ " n = 0; mini = -1",
14165
+ " }",
14166
+ " BEGIN { in_ac=0; total=0; n=0; mini=-1 }",
13990
14167
  " # Fully case-insensitive heading match mirrors the TypeScript",
13991
14168
  " # classifier (/^## acceptance criteria\\s*$/i); POSIX awk has",
13992
14169
  " # no /i flag, so we compare via tolower() instead of a",
13993
14170
  " # per-letter character class like [Aa]cceptance [Cc]riteria",
13994
14171
  " # which would drift for headings like `## ACCEPTANCE CRITERIA`.",
13995
14172
  " { lower = tolower($0) }",
13996
- " lower ~ /^## acceptance criteria[[:space:]]*$/ { in_ac=1; next }",
13997
- " /^## / { in_ac=0 }",
13998
- " in_ac && /^[[:space:]]*-[[:space:]]*\\[[ xX]\\]/ { count++ }",
13999
- " END { print count }",
14173
+ " lower ~ /^## acceptance criteria[[:space:]]*$/ { flush(); in_ac=1; next }",
14174
+ " /^## / { if (in_ac) { flush(); in_ac=0 } }",
14175
+ " in_ac && /^[[:space:]]*-[[:space:]]*\\[[ xX]\\]/ {",
14176
+ " match($0, /^[[:space:]]*/); ind = RLENGTH;",
14177
+ " indents[n++] = ind;",
14178
+ " if (mini < 0 || ind < mini) mini = ind;",
14179
+ " }",
14180
+ " END { flush(); print total }",
14000
14181
  " ')",
14001
14182
  ` sources_count=$(printf '%s\\n' "$body" | awk '`,
14002
14183
  " BEGIN { in_src=0; count=0 }",
@@ -14005,7 +14186,16 @@ function renderScopeGateShellHelpers(gate) {
14005
14186
  " { lower = tolower($0) }",
14006
14187
  " lower ~ /^## (inputs|references|sources)[[:space:]]*$/ { in_src=1; next }",
14007
14188
  " /^## / { in_src=0 }",
14008
- " in_src && /^[[:space:]]*[-*][[:space:]]+/ { count++ }",
14189
+ " # Exclude `Key: value` metadata bullets (e.g. `- Basename: \u2026`)",
14190
+ " # \u2014 a bullet whose text is a `Word:` key/value pair is",
14191
+ " # metadata, not a source. Mirrors the TS countSourceBullets()",
14192
+ " # METADATA_KEY_VALUE_REGEX exclusion.",
14193
+ " in_src && /^[[:space:]]*[-*][[:space:]]+/ {",
14194
+ " rest = $0;",
14195
+ ' sub(/^[[:space:]]*[-*][[:space:]]+/, "", rest);',
14196
+ " if (rest ~ /^[A-Za-z][A-Za-z0-9-]*:[[:space:]]+[^[:space:]]/) next;",
14197
+ " count++;",
14198
+ " }",
14009
14199
  " END { print count }",
14010
14200
  " ')",
14011
14201
  ` printf 'ac=%s sources=%s\\n' "$ac_count" "$sources_count" >&2`,
@@ -14160,37 +14350,80 @@ function resolveScopeClass(acCount, sourcesCount, thresholds) {
14160
14350
  }
14161
14351
  return "large";
14162
14352
  }
14353
+ var AC_CHECKBOX_REGEX = /^(\s*)-\s*\[[ xX]\]/;
14354
+ var SOURCES_BULLET_REGEX = /^\s*[-*]\s+(.*)$/;
14355
+ var METADATA_KEY_VALUE_REGEX = /^[A-Za-z][A-Za-z0-9-]*:\s+\S/;
14163
14356
  function countAcceptanceCriteria(body) {
14164
14357
  return countSectionMatches(
14165
14358
  body,
14166
14359
  /^## acceptance criteria\s*$/i,
14167
- /^\s*-\s*\[[ xX]\]/
14360
+ countTopLevelCheckboxes
14168
14361
  );
14169
14362
  }
14170
14363
  function countSources(body) {
14171
14364
  return countSectionMatches(
14172
14365
  body,
14173
14366
  /^## (?:inputs|references|sources)\s*$/i,
14174
- /^\s*[-*]\s+/
14367
+ countSourceBullets
14175
14368
  );
14176
14369
  }
14177
- function countSectionMatches(body, headingRegex, lineRegex) {
14370
+ function countTopLevelCheckboxes(sectionLines) {
14371
+ let minIndent = Infinity;
14372
+ const indents = [];
14373
+ for (const line of sectionLines) {
14374
+ const match = AC_CHECKBOX_REGEX.exec(line);
14375
+ if (match === null) {
14376
+ continue;
14377
+ }
14378
+ const indent = match[1].length;
14379
+ indents.push(indent);
14380
+ if (indent < minIndent) {
14381
+ minIndent = indent;
14382
+ }
14383
+ }
14384
+ return indents.filter((indent) => indent === minIndent).length;
14385
+ }
14386
+ function countSourceBullets(sectionLines) {
14387
+ let count = 0;
14388
+ for (const line of sectionLines) {
14389
+ const match = SOURCES_BULLET_REGEX.exec(line);
14390
+ if (match === null) {
14391
+ continue;
14392
+ }
14393
+ if (METADATA_KEY_VALUE_REGEX.test(match[1])) {
14394
+ continue;
14395
+ }
14396
+ count += 1;
14397
+ }
14398
+ return count;
14399
+ }
14400
+ function countSectionMatches(body, headingRegex, lineCounter) {
14178
14401
  const lines = body.split(/\r?\n/);
14179
14402
  let count = 0;
14180
14403
  let inSection = false;
14404
+ let sectionLines = [];
14405
+ const flush = () => {
14406
+ if (sectionLines.length > 0) {
14407
+ count += lineCounter(sectionLines);
14408
+ sectionLines = [];
14409
+ }
14410
+ };
14181
14411
  for (const line of lines) {
14182
14412
  if (headingRegex.test(line)) {
14413
+ flush();
14183
14414
  inSection = true;
14184
14415
  continue;
14185
14416
  }
14186
14417
  if (inSection && /^## /.test(line)) {
14418
+ flush();
14187
14419
  inSection = false;
14188
14420
  continue;
14189
14421
  }
14190
- if (inSection && lineRegex.test(line)) {
14191
- count += 1;
14422
+ if (inSection) {
14423
+ sectionLines.push(line);
14192
14424
  }
14193
14425
  }
14426
+ flush();
14194
14427
  return count;
14195
14428
  }
14196
14429
 
@@ -32379,7 +32612,7 @@ var DEFAULT_CLAUDE_HOOKS = {
32379
32612
  hooks: [
32380
32613
  {
32381
32614
  type: "command",
32382
- 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'
32615
+ 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'
32383
32616
  }
32384
32617
  ]
32385
32618
  }
@@ -32468,8 +32701,10 @@ var AgentConfig = class _AgentConfig extends Component8 {
32468
32701
  * `Array.from(new Set(...))`; V8 `Set` iteration preserves insertion
32469
32702
  * order, so the final ordering is defaults first, then bundle, then
32470
32703
  * user, with duplicates removed (first-occurrence wins). `defaultMode`
32471
- * defaults to `"dontAsk"` unless overridden see the inline comment
32472
- * on the literal below for the autonomous-worker rationale.
32704
+ * is opt-in (steering decision D7): it is set only from
32705
+ * `userSettings.defaultMode` and left undefined otherwise, so the
32706
+ * renderer omits the key for un-opted-in consumers — see the inline
32707
+ * comment on the literal below.
32473
32708
  *
32474
32709
  * Hooks merge: consumer-supplied entries first, then default entries
32475
32710
  * (Stop, PostToolUse), deduped by `(matcher, JSON-serialized hooks)`.
@@ -32492,15 +32727,16 @@ var AgentConfig = class _AgentConfig extends Component8 {
32492
32727
  const userDeny = userSettings?.permissions?.deny ?? [];
32493
32728
  return {
32494
32729
  ...userSettings,
32495
- // `defaultMode: "dontAsk"` is configulator's hardcoded default
32496
- // because scheduled-task workers (issue-worker, orchestrator,
32497
- // pr-reviewer, and the analyst/writer family) run autonomously
32498
- // and would deadlock on confirmation prompts. Any other value
32499
- // breaks the autonomous-worker contract override only after
32500
- // revisiting that contract end-to-end. The override path for
32501
- // consumers is `claudeSettings.defaultMode` on
32502
- // `AgentConfigOptions`.
32503
- defaultMode: userSettings?.defaultMode ?? "dontAsk",
32730
+ // `defaultMode` is opt-in (steering decision D7): the base
32731
+ // output does NOT set it unless the consumer supplies
32732
+ // `claudeSettings.defaultMode`. When it is undefined the renderer
32733
+ // omits the key entirely, so an un-opted-in consumer's rendered
32734
+ // settings carry no `defaultMode`. Consumers that run autonomous
32735
+ // scheduled-task workers (issue-worker, orchestrator, pr-reviewer,
32736
+ // and the analyst/writer family) — which would deadlock on
32737
+ // confirmation prompts — opt in by setting
32738
+ // `claudeSettings.defaultMode: "dontAsk"`.
32739
+ defaultMode: userSettings?.defaultMode,
32504
32740
  permissions: {
32505
32741
  ...userSettings?.permissions,
32506
32742
  allow: Array.from(
@@ -39433,6 +39669,7 @@ export {
39433
39669
  renderSkillEvalsRuleContent,
39434
39670
  renderSkillEvalsRunnerScript,
39435
39671
  renderSourceTierExamples,
39672
+ renderStripToolArtifactTagsProcedure,
39436
39673
  renderTemporalFramingCheckerScript,
39437
39674
  renderTemporalFramingRuleContent,
39438
39675
  renderUnblockDependentsScript,
@@ -39469,6 +39706,7 @@ export {
39469
39706
  slackBundle,
39470
39707
  softwareProfileBundle,
39471
39708
  standardsResearchBundle,
39709
+ stripToolArtifactTagsProcedure,
39472
39710
  tsdocRecordToFindings,
39473
39711
  turborepoBundle,
39474
39712
  typescriptBundle,