@codedrifters/configulator 0.0.271 → 0.0.273

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
@@ -8737,6 +8737,295 @@ var extractApiProcedure = {
8737
8737
  description: "Run @microsoft/api-extractor for a single package and write the .api.md rollup to the scratch folder declared by the package's api-extractor.json. Rollups are regenerate-on-scan per docs-sync epic #448 resolved decision #3 \u2014 never committed to git.",
8738
8738
  content: renderExtractApiProcedure()
8739
8739
  };
8740
+ function renderCheckLinksProcedure() {
8741
+ return [
8742
+ "#!/usr/bin/env bash",
8743
+ "# check-links.sh \u2014 Link integrity checker for the Starlight docs site.",
8744
+ "#",
8745
+ "# Usage:",
8746
+ "# .claude/procedures/check-links.sh <mode> <docs-root> [<site-dir>]",
8747
+ "#",
8748
+ "# Where:",
8749
+ "# <mode> \u2014 one of `internal`, `external`, or `all`.",
8750
+ "# <docs-root> \u2014 path to the markdown content tree",
8751
+ "# (e.g. `docs/src/content/docs`). Walked recursively",
8752
+ "# for `*.md` / `*.mdx` files.",
8753
+ "# <site-dir> \u2014 (optional, internal/all only) path to the Starlight",
8754
+ "# project root that contains `astro.config.{ts,mjs,js}`.",
8755
+ "# Defaults to two levels up from `<docs-root>` so the",
8756
+ "# standard Starlight layout (`<site>/src/content/docs`)",
8757
+ "# resolves automatically.",
8758
+ "#",
8759
+ "# Wraps two external tools:",
8760
+ "# - `astro check` \u2014 internal links and content-collection refs",
8761
+ "# inside the Starlight site.",
8762
+ "# - `lychee` \u2014 external `https://\u2026` URLs across the docs tree",
8763
+ "# (https://github.com/lycheeverse/lychee).",
8764
+ "#",
8765
+ "# Output (stdout, single JSON array):",
8766
+ "#",
8767
+ "# [",
8768
+ "# {",
8769
+ '# "url": "<href as written in the markdown source>",',
8770
+ '# "docPath": "<path relative to <docs-root>>",',
8771
+ '# "line": <1-indexed line number>,',
8772
+ '# "kind": "internal" | "external",',
8773
+ '# "reason": "<short tool-supplied diagnostic>"',
8774
+ "# },",
8775
+ "# ...",
8776
+ "# ]",
8777
+ "#",
8778
+ "# An empty array (`[]`) is emitted when no broken links are found.",
8779
+ "# Detection is **data**, not failure: this helper exits 0 when a",
8780
+ "# tool ran successfully and reported zero or more broken links.",
8781
+ "# The downstream docs-sync scan phase (#519/#520) is responsible",
8782
+ "# for deciding which findings are advisory and which block.",
8783
+ "#",
8784
+ "# Exit codes:",
8785
+ "# 0 \u2014 every requested tool ran successfully; findings (zero or",
8786
+ "# more) are on stdout as a JSON array.",
8787
+ "# 1 \u2014 usage error (missing args, unreadable docs root).",
8788
+ "# 2 \u2014 a required external tool is not installed or not on PATH",
8789
+ "# (`astro` / `lychee` / `node` / `jq`).",
8790
+ "# 3 \u2014 a tool ran but exited non-zero for a reason other than",
8791
+ "# broken-link detection (config error, IO error, network",
8792
+ "# failure for lychee, etc.). Stderr carries the diagnostic.",
8793
+ "#",
8794
+ "# The script never edits files. Diagnostics flow to stderr; the",
8795
+ "# only thing on stdout is the normalized JSON array.",
8796
+ "",
8797
+ "set -uo pipefail",
8798
+ "",
8799
+ "err() {",
8800
+ ' printf "check-links.sh: %s\\n" "$*" >&2',
8801
+ "}",
8802
+ "",
8803
+ 'if [ "$#" -lt 2 ]; then',
8804
+ ' err "usage: check-links.sh <internal|external|all> <docs-root> [<site-dir>]"',
8805
+ " exit 1",
8806
+ "fi",
8807
+ "",
8808
+ 'mode="$1"',
8809
+ 'docs_root="$2"',
8810
+ 'site_dir="${3:-}"',
8811
+ "",
8812
+ 'case "$mode" in',
8813
+ " internal | external | all) ;;",
8814
+ " *)",
8815
+ ` err "unknown mode '$mode' \u2014 expected 'internal', 'external', or 'all'"`,
8816
+ " exit 1",
8817
+ " ;;",
8818
+ "esac",
8819
+ "",
8820
+ 'if [ ! -d "$docs_root" ]; then',
8821
+ ' err "docs root not found: $docs_root"',
8822
+ " exit 1",
8823
+ "fi",
8824
+ "",
8825
+ 'if [ -z "$site_dir" ]; then',
8826
+ " # Standard Starlight layout: <site>/src/content/docs. Walk two",
8827
+ " # parents up from the content root to recover the site dir.",
8828
+ ' site_dir="$(cd "$docs_root/../../.." && pwd)"',
8829
+ "fi",
8830
+ "",
8831
+ "# `jq` is required to merge the per-tool JSON output streams. Fail",
8832
+ "# fast with the dedicated tool-missing exit code if it is absent.",
8833
+ "if ! command -v jq >/dev/null 2>&1; then",
8834
+ ' err "jq is required but not on PATH"',
8835
+ " exit 2",
8836
+ "fi",
8837
+ "",
8838
+ 'tmp_dir="$(mktemp -d -t check-links-XXXXXX)"',
8839
+ "# shellcheck disable=SC2064",
8840
+ `trap "rm -rf '$tmp_dir'" EXIT`,
8841
+ "",
8842
+ 'internal_json="$tmp_dir/internal.json"',
8843
+ 'external_json="$tmp_dir/external.json"',
8844
+ 'printf "[]" > "$internal_json"',
8845
+ 'printf "[]" > "$external_json"',
8846
+ "",
8847
+ "# ---------------------------------------------------------------",
8848
+ "# Internal-link check",
8849
+ "# ---------------------------------------------------------------",
8850
+ "# `astro check` runs inside the Starlight project root and walks",
8851
+ "# content collections to validate internal references. It exits",
8852
+ "# non-zero when references are broken \u2014 that is a *finding* for",
8853
+ "# this helper, not a tool failure, so we capture stderr and parse",
8854
+ "# it into the normalized record shape rather than propagating the",
8855
+ "# non-zero exit.",
8856
+ 'if [ "$mode" = "internal" ] || [ "$mode" = "all" ]; then',
8857
+ " if ! command -v node >/dev/null 2>&1; then",
8858
+ ' err "node is required but not on PATH"',
8859
+ " exit 2",
8860
+ " fi",
8861
+ "",
8862
+ ' if [ ! -d "$site_dir" ]; then',
8863
+ ' err "site dir not found: $site_dir"',
8864
+ " exit 1",
8865
+ " fi",
8866
+ "",
8867
+ " # Locate the astro binary in the site's local node_modules first",
8868
+ " # so the version matches what `pnpm install` resolved for the",
8869
+ " # Starlight site. Fall back to a workspace-aware `pnpm exec`.",
8870
+ ' if [ -x "$site_dir/node_modules/.bin/astro" ]; then',
8871
+ ' astro_bin=("$site_dir/node_modules/.bin/astro")',
8872
+ " elif command -v pnpm >/dev/null 2>&1; then",
8873
+ ' astro_bin=(pnpm --dir "$site_dir" exec astro)',
8874
+ " else",
8875
+ ' err "astro binary not found in $site_dir/node_modules/.bin and pnpm is unavailable"',
8876
+ " exit 2",
8877
+ " fi",
8878
+ "",
8879
+ ' astro_log="$tmp_dir/astro.log"',
8880
+ " set +e",
8881
+ ' ( cd "$site_dir" && "${astro_bin[@]}" check ) > "$astro_log" 2>&1',
8882
+ " astro_status=$?",
8883
+ " set -e",
8884
+ "",
8885
+ " # `astro check` exits 1 on findings and >=2 on tool failure.",
8886
+ " # Translate to the normalized record stream regardless of exit.",
8887
+ ' if [ "$astro_status" -ge 2 ]; then',
8888
+ ' err "astro check exited with status $astro_status (tool failure)"',
8889
+ ' cat "$astro_log" >&2 || true',
8890
+ " exit 3",
8891
+ " fi",
8892
+ "",
8893
+ " # Parse the line-oriented log into JSON records. The `astro",
8894
+ " # check` output for a broken reference looks like:",
8895
+ " #",
8896
+ " # src/content/docs/foo.md:42:8 - error <code>: <reason>",
8897
+ " #",
8898
+ " # The helper extracts `<docPath>`, `<line>`, and `<reason>` and",
8899
+ " # synthesises a `url` field by quoting the offending excerpt",
8900
+ " # when astro reports one (it does not always); when no excerpt",
8901
+ " # is available we fall back to an empty string so the schema",
8902
+ " # stays uniform.",
8903
+ ` awk -v docs_root="$docs_root" -v site_dir="$site_dir" '`,
8904
+ " BEGIN {",
8905
+ ' printf "[";',
8906
+ " first = 1;",
8907
+ " }",
8908
+ ' # Match "<path>:<line>:<col> - <severity> <code>: <message>"',
8909
+ " /^.+:[0-9]+:[0-9]+ - / {",
8910
+ ' split($0, head, " - ");',
8911
+ ' n = split(head[1], loc, ":");',
8912
+ " file = loc[1];",
8913
+ ' for (i = 2; i < n - 1; i++) { file = file ":" loc[i]; }',
8914
+ " line = loc[n - 1];",
8915
+ ' message = "";',
8916
+ " for (i = 2; i <= length(head); i++) {",
8917
+ ' if (i > 2) message = message " - ";',
8918
+ " message = message head[i];",
8919
+ " }",
8920
+ " # Resolve the file relative to docs_root for stability.",
8921
+ " abs = file;",
8922
+ ' if (substr(abs, 1, 1) != "/") {',
8923
+ ' abs = site_dir "/" abs;',
8924
+ " }",
8925
+ ' sub(docs_root "/", "", abs);',
8926
+ ' gsub(/"/, "\\\\\\"", message);',
8927
+ ' gsub(/"/, "\\\\\\"", abs);',
8928
+ ' if (!first) printf ",";',
8929
+ " first = 0;",
8930
+ ' printf "{\\"url\\":\\"\\",\\"docPath\\":\\"%s\\",\\"line\\":%s,\\"kind\\":\\"internal\\",\\"reason\\":\\"%s\\"}", abs, line, message;',
8931
+ " }",
8932
+ " END {",
8933
+ ' printf "]";',
8934
+ " }",
8935
+ ` ' "$astro_log" > "$internal_json"`,
8936
+ "",
8937
+ " # Validate the JSON we synthesised. Catches awk escaping bugs",
8938
+ " # before we hand the payload to the merge step.",
8939
+ ' if ! jq -e . "$internal_json" >/dev/null 2>&1; then',
8940
+ ' err "failed to normalize astro check output to JSON"',
8941
+ ' cat "$internal_json" >&2 || true',
8942
+ " exit 3",
8943
+ " fi",
8944
+ "fi",
8945
+ "",
8946
+ "# ---------------------------------------------------------------",
8947
+ "# External-link check",
8948
+ "# ---------------------------------------------------------------",
8949
+ "# `lychee` walks the markdown tree and reports unreachable URLs.",
8950
+ "# Its `--format json` output is structured per-link; we project",
8951
+ "# only the failed entries into the normalized record shape.",
8952
+ 'if [ "$mode" = "external" ] || [ "$mode" = "all" ]; then',
8953
+ " if ! command -v lychee >/dev/null 2>&1; then",
8954
+ ' err "lychee is required but not on PATH (https://github.com/lycheeverse/lychee)"',
8955
+ " exit 2",
8956
+ " fi",
8957
+ "",
8958
+ ' lychee_json="$tmp_dir/lychee.json"',
8959
+ " set +e",
8960
+ " # `--no-progress` avoids interactive carriage-returns mangling",
8961
+ " # the JSON. `--format json` emits a single object whose `fail_map`",
8962
+ " # field lists the broken URLs grouped by source file.",
8963
+ " # `--exclude-mail` skips mailto: links (out of scope for this",
8964
+ " # helper).",
8965
+ ' lychee --no-progress --format json --exclude-mail "$docs_root" > "$lychee_json" 2>"$tmp_dir/lychee.err"',
8966
+ " lychee_status=$?",
8967
+ " set -e",
8968
+ "",
8969
+ " # lychee exits 0 when every link resolved, 2 when one or more",
8970
+ " # links failed. Anything else is a tool failure (config, IO).",
8971
+ ' if [ "$lychee_status" -ne 0 ] && [ "$lychee_status" -ne 2 ]; then',
8972
+ ' err "lychee exited with status $lychee_status (tool failure)"',
8973
+ ' cat "$tmp_dir/lychee.err" >&2 || true',
8974
+ " exit 3",
8975
+ " fi",
8976
+ "",
8977
+ " # Project lychee's `fail_map` into the normalized record shape.",
8978
+ ' # The `fail_map` is `{ "<source-path>": [ { url, status: { details? } }, ... ] }`.',
8979
+ " # lychee does not report a line number for every match, so we",
8980
+ " # default to 0 when it is missing (downstream consumers treat",
8981
+ ' # 0 as "unknown line").',
8982
+ ` jq --arg root "$docs_root" '`,
8983
+ " def trim_root($p; $r):",
8984
+ ' if ($p | startswith($r + "/")) then ($p | ltrimstr($r + "/"))',
8985
+ ' elif ($p == $r) then ""',
8986
+ " else $p end;",
8987
+ " [",
8988
+ " ( .fail_map // {} ) as $map",
8989
+ " | $map | to_entries[]",
8990
+ " | .key as $src",
8991
+ " | .value[]",
8992
+ " | {",
8993
+ ' url: (.url // ""),',
8994
+ " docPath: trim_root($src; $root),",
8995
+ " line: ((.line // 0) | tonumber? // 0),",
8996
+ ' kind: "external",',
8997
+ ' reason: ( (.status.details // .status.text // .status.code // "broken") | tostring )',
8998
+ " }",
8999
+ " ]",
9000
+ ` ' "$lychee_json" > "$external_json" 2>"$tmp_dir/lychee.parse.err"`,
9001
+ "",
9002
+ ' if ! jq -e . "$external_json" >/dev/null 2>&1; then',
9003
+ ' err "failed to parse lychee JSON output"',
9004
+ ' cat "$tmp_dir/lychee.parse.err" >&2 || true',
9005
+ ' cat "$lychee_json" >&2 || true',
9006
+ " exit 3",
9007
+ " fi",
9008
+ "fi",
9009
+ "",
9010
+ "# ---------------------------------------------------------------",
9011
+ "# Merge & emit",
9012
+ "# ---------------------------------------------------------------",
9013
+ "# Sort records deterministically (kind, docPath, line, url) so",
9014
+ "# downstream consumers can compare reports across runs without",
9015
+ "# fighting platform-specific ordering noise.",
9016
+ "jq -s '",
9017
+ " add",
9018
+ " | sort_by(.kind, .docPath, .line, .url)",
9019
+ `' "$internal_json" "$external_json"`,
9020
+ "",
9021
+ "exit 0"
9022
+ ].join("\n");
9023
+ }
9024
+ var checkLinksProcedure = {
9025
+ name: "check-links.sh",
9026
+ 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.",
9027
+ content: renderCheckLinksProcedure()
9028
+ };
8740
9029
  function buildDocsSyncBundle(paths = DEFAULT_AGENT_PATHS) {
8741
9030
  return {
8742
9031
  name: "docs-sync",
@@ -8786,7 +9075,7 @@ function buildDocsSyncBundle(paths = DEFAULT_AGENT_PATHS) {
8786
9075
  ],
8787
9076
  skills: [buildDocsSyncPrSkill(), buildDocsSyncAuditSkill()],
8788
9077
  subAgents: [buildDocsSyncSubAgent(paths)],
8789
- procedures: [extractApiProcedure],
9078
+ procedures: [extractApiProcedure, checkLinksProcedure],
8790
9079
  labels: [
8791
9080
  {
8792
9081
  name: "type:docs-sync",
@@ -29012,6 +29301,7 @@ var JsiiFaker = class _JsiiFaker extends Component13 {
29012
29301
 
29013
29302
  // src/projects/astro-project.ts
29014
29303
  import { SampleFile as SampleFile2 } from "projen";
29304
+ import { merge as merge3 } from "ts-deepmerge";
29015
29305
 
29016
29306
  // src/projects/monorepo-layout.ts
29017
29307
  var MONOREPO_LAYOUT = {
@@ -30205,20 +30495,27 @@ var TypeScriptProject = class extends typescript.TypeScriptProject {
30205
30495
  var AstroProject = class extends TypeScriptProject {
30206
30496
  constructor(userOptions) {
30207
30497
  const resolvedOutdir = userOptions.outdir ?? resolveAstroProjectOutdir(userOptions.packageName ?? userOptions.name);
30208
- const options = {
30498
+ const defaultOptions = {
30209
30499
  testRunner: TestRunner.VITEST,
30210
30500
  // Astro sites don't expose a library API surface — skip the
30211
30501
  // `@microsoft/api-extractor` wiring the TypeScriptProject base adds
30212
30502
  // by default. Callers can opt in with `apiExtractor: { ... }` if a
30213
30503
  // given site genuinely ships typed re-exports.
30214
30504
  apiExtractor: false,
30215
- ...userOptions,
30216
- outdir: resolvedOutdir,
30505
+ tsconfig: {
30506
+ compilerOptions: {
30507
+ declaration: false
30508
+ }
30509
+ },
30217
30510
  depsUpgradeOptions: {
30218
- ...userOptions.depsUpgradeOptions,
30219
- exclude: [...userOptions.depsUpgradeOptions?.exclude ?? [], "astro"]
30511
+ exclude: ["astro"]
30220
30512
  }
30221
30513
  };
30514
+ const merged = merge3(defaultOptions, userOptions);
30515
+ const options = {
30516
+ ...merged,
30517
+ outdir: resolvedOutdir
30518
+ };
30222
30519
  super(options);
30223
30520
  const astroVersion = options.astroVersion ?? VERSION.ASTRO_VERSION;
30224
30521
  const astroTsconfigExtends = options.astroTsconfigExtends ?? "astro/tsconfigs/strict";
@@ -30270,6 +30567,9 @@ var AstroProject = class extends TypeScriptProject {
30270
30567
  parser: "astro-eslint-parser"
30271
30568
  });
30272
30569
  this.eslint?.addLintPattern("src/**/*.astro");
30570
+ this.eslint?.addRules({
30571
+ "import/no-unresolved": ["error", { ignore: ["^astro:"] }]
30572
+ });
30273
30573
  this.gitignore.addPatterns(".astro", ".vercel", ".netlify");
30274
30574
  const turbo = TurboRepo.of(this);
30275
30575
  if (turbo?.compileTask) {
@@ -30319,7 +30619,7 @@ import {
30319
30619
  UpgradeDependenciesSchedule as UpgradeDependenciesSchedule3
30320
30620
  } from "projen/lib/javascript";
30321
30621
  import { ReleaseTrigger as ReleaseTrigger2 } from "projen/lib/release";
30322
- import { merge as merge3 } from "ts-deepmerge";
30622
+ import { merge as merge4 } from "ts-deepmerge";
30323
30623
 
30324
30624
  // src/workflows/aws-deploy-workflow.ts
30325
30625
  var import_utils11 = __toESM(require_lib());
@@ -30889,7 +31189,7 @@ var AwsCdkProject = class extends awscdk.AwsCdkTypeScriptApp {
30889
31189
  paths: [`${resolvedOutdir}/src/**`, `${resolvedOutdir}/package.json`]
30890
31190
  })
30891
31191
  };
30892
- const options = merge3(defaultOptions, userOptions);
31192
+ const options = merge4(defaultOptions, userOptions);
30893
31193
  super(options);
30894
31194
  this.addDevDeps("@types/node@catalog:");
30895
31195
  this.tsconfig?.addExclude("**/*.test.*");
@@ -30961,7 +31261,7 @@ var AwsCdkProject = class extends awscdk.AwsCdkTypeScriptApp {
30961
31261
  ]
30962
31262
  };
30963
31263
  const userResetTaskOptions = options.resetTaskOptions ?? {};
30964
- const resetTaskOptions = merge3(
31264
+ const resetTaskOptions = merge4(
30965
31265
  defaultResetTaskOptions,
30966
31266
  {
30967
31267
  ...userResetTaskOptions,
@@ -31038,7 +31338,7 @@ var StarlightProject = class extends AstroProject {
31038
31338
  new SampleFile3(this, "src/content/docs/index.mdx", {
31039
31339
  contents: DEFAULT_INDEX_MDX
31040
31340
  });
31041
- new SampleFile3(this, "src/content/config.ts", {
31341
+ new SampleFile3(this, "src/content.config.ts", {
31042
31342
  contents: DEFAULT_CONTENT_CONFIG_TS
31043
31343
  });
31044
31344
  }
@@ -31078,10 +31378,11 @@ description: Starlight-powered documentation site.
31078
31378
  Edit \`src/content/docs/index.mdx\` to replace this page.
31079
31379
  `;
31080
31380
  var DEFAULT_CONTENT_CONFIG_TS = `import { defineCollection } from "astro:content";
31381
+ import { docsLoader } from "@astrojs/starlight/loaders";
31081
31382
  import { docsSchema } from "@astrojs/starlight/schema";
31082
31383
 
31083
31384
  export const collections = {
31084
- docs: defineCollection({ schema: docsSchema() }),
31385
+ docs: defineCollection({ loader: docsLoader(), schema: docsSchema() }),
31085
31386
  };
31086
31387
  `;
31087
31388
 
@@ -31250,6 +31551,7 @@ export {
31250
31551
  buildStandardsResearchBundle,
31251
31552
  buildUnblockDependentsProcedure,
31252
31553
  businessModelsBundle,
31554
+ checkLinksProcedure,
31253
31555
  classifyIssueScope,
31254
31556
  classifyRun,
31255
31557
  companyProfileBundle,
@@ -31273,6 +31575,7 @@ export {
31273
31575
  regulatoryResearchBundle,
31274
31576
  renderAgentTierCaseStatement,
31275
31577
  renderAgentTierSection,
31578
+ renderCheckLinksProcedure,
31276
31579
  renderCustomDocSectionBlock,
31277
31580
  renderCustomDocSections,
31278
31581
  renderExtractApiProcedure,