code-foundry 0.1.4 → 0.2.0

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.
@@ -91,12 +91,14 @@ NODE
91
91
 
92
92
  package_manager() {
93
93
  local configured=""
94
- if [ -f .github/template.yml ]; then
94
+ if [ -x .github/scripts/profile.sh ]; then
95
+ configured="$(bash .github/scripts/profile.sh get package_manager 2>/dev/null || true)"
96
+ elif [ -f .github/template.yml ]; then
95
97
  configured="$(awk -F': ' '/^package_manager:/ {print $2; exit}' .github/template.yml)"
96
- case "$configured" in
97
- bun|pnpm|yarn|npm) echo "$configured"; return ;;
98
- esac
99
98
  fi
99
+ case "$configured" in
100
+ bun|pnpm|yarn|npm) echo "$configured"; return ;;
101
+ esac
100
102
  if [ -f bun.lock ] || [ -f bun.lockb ]; then echo bun
101
103
  elif [ -f pnpm-lock.yaml ]; then echo pnpm
102
104
  elif [ -f yarn.lock ]; then echo yarn
@@ -23,7 +23,9 @@ esac
23
23
 
24
24
  if find .github/workflows -type f \( -name '*.yml' -o -name '*.yaml' \) -print -quit | grep -q .; then languages+=(actions); fi
25
25
  configured=""
26
- if [ -f .github/template.yml ]; then
26
+ if [ -x .github/scripts/profile.sh ]; then
27
+ configured="$(bash .github/scripts/profile.sh get languages 2>/dev/null || true)"
28
+ elif [ -f .github/template.yml ]; then
27
29
  configured="$(awk -F': ' '/^languages:/ {print $2; exit}' .github/template.yml)"
28
30
  fi
29
31
 
@@ -91,7 +91,7 @@ for workflow in ci codeql security test draft-pr release-pr release; do
91
91
  fi
92
92
  done
93
93
 
94
- for script in ci.sh codeql-languages.sh security.sh doctor.sh bootstrap.sh sync-template.sh init-repo.sh sync-protection.sh sync-codeowners.sh; do
94
+ for script in ci.sh codeql-languages.sh profile.sh security.sh doctor.sh bootstrap.sh sync-template.sh init-repo.sh sync-protection.sh sync-codeowners.sh; do
95
95
  [ -x ".github/scripts/$script" ] || error "missing executable script: .github/scripts/$script"
96
96
  done
97
97
 
@@ -3,15 +3,16 @@ set -euo pipefail
3
3
 
4
4
  source="${REPO_FOUNDRY_SOURCE:-https://github.com/${GITHUB_REPOSITORY_OWNER:-OWNER}/code-foundry.git}"
5
5
  ref="main"
6
+ profile="${REPO_FOUNDRY_PROFILE:-auto}"
6
7
  protection=false
7
8
  dry_run=false
8
9
  prune=false
9
- languages="auto"
10
- features="all"
11
- package_manager="auto"
10
+ languages="${REPO_FOUNDRY_LANGUAGES:-auto}"
11
+ features="${REPO_FOUNDRY_FEATURES:-all}"
12
+ package_manager="${REPO_FOUNDRY_PACKAGE_MANAGER:-auto}"
12
13
  bootstrap=true
13
- release_type="auto"
14
- npm_publish="false"
14
+ release_type="${REPO_FOUNDRY_RELEASE_TYPE:-auto}"
15
+ npm_publish="${REPO_FOUNDRY_NPM_PUBLISH:-false}"
15
16
  tool_dir=""
16
17
 
17
18
  cleanup() {
@@ -28,6 +29,7 @@ Initialize or synchronize a repository from the shared baseline.
28
29
  Options:
29
30
  --source PATH_OR_URL Template source (default: REPO_FOUNDRY_SOURCE or GitHub owner)
30
31
  --ref REF Template branch or tag (default: main)
32
+ --profile NAME auto, application, monorepo, or minimal
31
33
  --languages LIST auto or comma-separated: typescript,rust,python,solidity
32
34
  --features LIST all or comma-separated optional features:
33
35
  ci,codeql,security,test,draft-pr,release-pr,release,dependabot
@@ -51,6 +53,7 @@ while [ "$#" -gt 0 ]; do
51
53
  case "$1" in
52
54
  --source) source="${2:?missing source path or URL}"; shift 2 ;;
53
55
  --ref) ref="${2:?missing ref}"; shift 2 ;;
56
+ --profile) profile="${2:?missing profile}"; shift 2 ;;
54
57
  --languages) languages="${2:?missing language list}"; shift 2 ;;
55
58
  --features) features="${2:?missing feature list}"; shift 2 ;;
56
59
  --package-manager) package_manager="${2:?missing package manager}"; shift 2 ;;
@@ -92,6 +95,7 @@ fi
92
95
  sync_args=(
93
96
  --source "$source"
94
97
  --ref "$ref"
98
+ --profile "$profile"
95
99
  --languages "$languages"
96
100
  --features "$features"
97
101
  --package-manager "$package_manager"
@@ -107,11 +111,18 @@ fi
107
111
 
108
112
  mkdir -p .github
109
113
  template_ref="$(awk -F': ' '/^template:/ {print $2; exit}' .github/template.yml 2>/dev/null || true)"
114
+ profile="$(awk -F': ' '/^profile:/ {print $2; exit}' .github/template.yml 2>/dev/null || true)"
115
+ languages="$(awk -F': ' '/^languages:/ {print $2; exit}' .github/template.yml 2>/dev/null || true)"
116
+ features="$(awk -F': ' '/^features:/ {print $2; exit}' .github/template.yml 2>/dev/null || true)"
117
+ package_manager="$(awk -F': ' '/^package_manager:/ {print $2; exit}' .github/template.yml 2>/dev/null || true)"
118
+ release_type="$(awk -F': ' '/^release_type:/ {print $2; exit}' .github/template.yml 2>/dev/null || true)"
119
+ npm_publish="$(awk -F': ' '/^npm_publish:/ {print $2; exit}' .github/template.yml 2>/dev/null || true)"
110
120
  {
111
121
  printf 'version: 1\n'
112
122
  if [ -n "$template_ref" ]; then
113
123
  printf 'template: %s\n' "$template_ref"
114
124
  fi
125
+ printf 'profile: %s\n' "$profile"
115
126
  printf 'languages: %s\n' "$languages"
116
127
  printf 'features: %s\n' "$features"
117
128
  printf 'package_manager: %s\n' "$package_manager"
@@ -0,0 +1,179 @@
1
+ #!/usr/bin/env bash
2
+ set -euo pipefail
3
+
4
+ # Resolve repository settings with this precedence:
5
+ # explicit REPO_FOUNDRY_* values (CLI callers can export them), then
6
+ # .github/template.yml, then detected defaults.
7
+
8
+ root="${REPO_FOUNDRY_ROOT:-$PWD}"
9
+ command="detect"
10
+ requested_key=""
11
+
12
+ usage() {
13
+ cat <<'EOF'
14
+ Usage: profile.sh [detect|env|get KEY] [--root PATH]
15
+
16
+ Commands:
17
+ detect Print the resolved profile as key=value lines (default)
18
+ env Print REPO_FOUNDRY_* assignments
19
+ get KEY Print one resolved profile value
20
+ EOF
21
+ }
22
+
23
+ while [ "$#" -gt 0 ]; do
24
+ case "$1" in
25
+ detect|env) command="$1"; shift ;;
26
+ get) command=get; requested_key="${2:?missing profile key}"; shift 2 ;;
27
+ --root) root="${2:?missing root path}"; shift 2 ;;
28
+ -h|--help) usage; exit 0 ;;
29
+ *) printf 'Unknown option: %s\n' "$1" >&2; exit 2 ;;
30
+ esac
31
+ done
32
+
33
+ cd "$root"
34
+ template_file=.github/template.yml
35
+
36
+ config_value() {
37
+ local key="$1"
38
+ [ -f "$template_file" ] || return 0
39
+ awk -F': *' -v key="$key" '$1 == key { print substr($0, index($0, ":") + 1); exit }' "$template_file" |
40
+ sed -e 's/^ *//' -e 's/ *$//' -e 's/^['"'"'"]//' -e 's/['"'"'"]$//'
41
+ }
42
+
43
+ env_value() {
44
+ local key="$1" env_key
45
+ env_key="REPO_FOUNDRY_$(printf '%s' "$key" | tr '[:lower:]-' '[:upper:]_')"
46
+ if [ -n "${!env_key+x}" ] && [ -n "${!env_key}" ]; then
47
+ printf '%s\n' "${!env_key}"
48
+ fi
49
+ }
50
+
51
+ raw_value() {
52
+ local key="$1" default="${2:-}" value
53
+ value="$(env_value "$key" || true)"
54
+ [ -n "$value" ] || value="$(config_value "$key" || true)"
55
+ [ -n "$value" ] && printf '%s\n' "$value" || printf '%s\n' "$default"
56
+ }
57
+
58
+ has_source() {
59
+ find . -path './.git' -prune -o -type f -print |
60
+ awk -v pattern="(^|/)[^/]+\\.($1)$" '$0 ~ pattern { found=1; exit } END { exit !found }'
61
+ }
62
+
63
+ detect_languages() {
64
+ local detected=()
65
+ if [ -f package.json ] || has_source 'js|jsx|mjs|cjs|ts|tsx|mts|cts' ||
66
+ [ -f bun.lock ] || [ -f bun.lockb ] || [ -f pnpm-lock.yaml ] ||
67
+ [ -f yarn.lock ] || [ -f package-lock.json ]; then
68
+ detected+=(typescript)
69
+ fi
70
+ if [ -f Cargo.toml ] || has_source 'rs'; then detected+=(rust); fi
71
+ if [ -f pyproject.toml ] || [ -f requirements.txt ] || [ -f requirements-dev.txt ] || has_source 'py'; then
72
+ detected+=(python)
73
+ fi
74
+ if find . -path './.git' -prune -o -type f -name '*.sol' -print -quit | grep -q .; then
75
+ detected+=(solidity)
76
+ fi
77
+ (IFS=,; printf '%s\n' "${detected[*]:-none}")
78
+ }
79
+
80
+ detect_package_manager() {
81
+ if [ -f bun.lock ] || [ -f bun.lockb ]; then echo bun
82
+ elif [ -f pnpm-lock.yaml ]; then echo pnpm
83
+ elif [ -f yarn.lock ]; then echo yarn
84
+ elif [ -f package-lock.json ]; then echo npm
85
+ elif [ -f package.json ]; then echo bun
86
+ else echo none
87
+ fi
88
+ }
89
+
90
+ detect_profile() {
91
+ if [ -f turbo.json ] || [ -f pnpm-workspace.yaml ] ||
92
+ ( [ -f package.json ] && node -e 'const p=require("./package.json"); process.exit(Array.isArray(p.workspaces) || (p.workspaces && typeof p.workspaces === "object") ? 0 : 1)' 2>/dev/null ); then
93
+ echo monorepo
94
+ elif [ -f package.json ] || [ -f pyproject.toml ] || [ -f Cargo.toml ]; then
95
+ echo application
96
+ else
97
+ echo minimal
98
+ fi
99
+ }
100
+
101
+ resolve_languages() {
102
+ local value
103
+ value="$(raw_value languages auto)"
104
+ [ "$value" = auto ] && value="$(detect_languages)"
105
+ printf '%s\n' "$value"
106
+ }
107
+
108
+ resolve_profile() {
109
+ local value
110
+ value="$(raw_value profile auto)"
111
+ [ "$value" = auto ] && value="$(detect_profile)"
112
+ printf '%s\n' "$value"
113
+ }
114
+
115
+ resolve_package_manager() {
116
+ local value
117
+ value="$(raw_value package_manager auto)"
118
+ [ "$value" = auto ] && value="$(detect_package_manager)"
119
+ printf '%s\n' "$value"
120
+ }
121
+
122
+ resolve_release_type() {
123
+ local value
124
+ value="$(raw_value release_type auto)"
125
+ if [ "$value" = auto ]; then
126
+ if [ -f package.json ]; then value=node
127
+ elif [ -f pyproject.toml ]; then value=python
128
+ elif [ -f Cargo.toml ]; then value=rust
129
+ elif [ -f version.txt ]; then value=simple
130
+ else value=none
131
+ fi
132
+ fi
133
+ printf '%s\n' "$value"
134
+ }
135
+
136
+ resolve_npm_publish() {
137
+ local value release_type
138
+ value="$(raw_value npm_publish false)"
139
+ release_type="$(resolve_release_type)"
140
+ [ "$release_type" = node ] || value=false
141
+ printf '%s\n' "$value"
142
+ }
143
+
144
+ detect() {
145
+ local profile languages package_manager release_type npm_publish features runner unit_runner
146
+ profile="$(resolve_profile)"
147
+ languages="$(resolve_languages)"
148
+ package_manager="$(resolve_package_manager)"
149
+ release_type="$(resolve_release_type)"
150
+ npm_publish="$(resolve_npm_publish)"
151
+ features="$(raw_value features all)"
152
+ runner="$(raw_value runner ubuntu-latest)"
153
+ unit_runner="$(raw_value unit_runner ubuntu-slim)"
154
+ printf 'profile=%s\n' "$profile"
155
+ printf 'languages=%s\n' "$languages"
156
+ printf 'features=%s\n' "$features"
157
+ printf 'package_manager=%s\n' "$package_manager"
158
+ printf 'release_type=%s\n' "$release_type"
159
+ printf 'npm_publish=%s\n' "$npm_publish"
160
+ printf 'runner=%s\n' "$runner"
161
+ printf 'unit_runner=%s\n' "$unit_runner"
162
+ printf 'cache_packages=%s\n' "$(raw_value cache_packages auto)"
163
+ printf 'cache_build=%s\n' "$(raw_value cache_build auto)"
164
+ printf 'coverage_minimum=%s\n' "$(raw_value coverage_minimum 80)"
165
+ printf 'turbo_remote=%s\n' "$(raw_value turbo_remote auto)"
166
+ }
167
+
168
+ case "$command" in
169
+ detect) detect ;;
170
+ get)
171
+ detect | awk -F= -v key="$requested_key" '$1 == key { print substr($0, index($0, "=") + 1); found=1 } END { exit !found }'
172
+ ;;
173
+ env)
174
+ detect | while IFS='=' read -r key value; do
175
+ env_key="REPO_FOUNDRY_$(printf '%s' "$key" | tr '[:lower:]-' '[:upper:]_')"
176
+ printf '%s=%q\n' "$env_key" "$value"
177
+ done
178
+ ;;
179
+ esac
@@ -103,12 +103,14 @@ run_parallel() {
103
103
 
104
104
  package_manager() {
105
105
  local configured=""
106
- if [ -f .github/template.yml ]; then
106
+ if [ -x .github/scripts/profile.sh ]; then
107
+ configured="$(bash .github/scripts/profile.sh get package_manager 2>/dev/null || true)"
108
+ elif [ -f .github/template.yml ]; then
107
109
  configured="$(awk -F': ' '/^package_manager:/ {print $2; exit}' .github/template.yml)"
108
- case "$configured" in
109
- bun|pnpm|yarn|npm) echo "$configured"; return ;;
110
- esac
111
110
  fi
111
+ case "$configured" in
112
+ bun|pnpm|yarn|npm) echo "$configured"; return ;;
113
+ esac
112
114
  if [ -f bun.lock ] || [ -f bun.lockb ]; then echo bun
113
115
  elif [ -f pnpm-lock.yaml ]; then echo pnpm
114
116
  elif [ -f yarn.lock ]; then echo yarn
@@ -9,6 +9,7 @@ Synchronize the repository-owned baseline without replacing project-specific
9
9
  README files, mise tool selections, or additional workflows.
10
10
 
11
11
  Options:
12
+ --profile NAME auto, application, monorepo, or minimal
12
13
  --languages LIST auto or comma-separated: typescript,rust,python,solidity
13
14
  --features LIST all or comma-separated standard features
14
15
  --package-manager NAME auto, bun, pnpm, yarn, or npm
@@ -22,16 +23,26 @@ source_ref="main"
22
23
  mode="check"
23
24
  source=""
24
25
  temp_dir=""
25
- languages="auto"
26
- features="all"
26
+ profile="${REPO_FOUNDRY_PROFILE:-auto}"
27
+ languages="${REPO_FOUNDRY_LANGUAGES:-auto}"
28
+ features="${REPO_FOUNDRY_FEATURES:-all}"
27
29
  prune=false
28
30
  languages_set=false
31
+ profile_set=false
29
32
  features_set=false
30
- package_manager=""
33
+ [ -n "${REPO_FOUNDRY_LANGUAGES:-}" ] && languages_set=true
34
+ [ -n "${REPO_FOUNDRY_PROFILE:-}" ] && profile_set=true
35
+ [ -n "${REPO_FOUNDRY_FEATURES:-}" ] && features_set=true
36
+ package_manager="${REPO_FOUNDRY_PACKAGE_MANAGER:-}"
31
37
  package_manager_set=false
38
+ [ -n "${REPO_FOUNDRY_PACKAGE_MANAGER:-}" ] && package_manager_set=true
32
39
  template_ref=""
33
- release_type="auto"
34
- npm_publish="false"
40
+ release_type="${REPO_FOUNDRY_RELEASE_TYPE:-auto}"
41
+ npm_publish="${REPO_FOUNDRY_NPM_PUBLISH:-false}"
42
+ release_type_set=false
43
+ npm_publish_set=false
44
+ [ -n "${REPO_FOUNDRY_RELEASE_TYPE:-}" ] && release_type_set=true
45
+ [ -n "${REPO_FOUNDRY_NPM_PUBLISH:-}" ] && npm_publish_set=true
35
46
  node_version="24.18.0"
36
47
  bun_version="1.3.14"
37
48
  python_version="3.13"
@@ -43,6 +54,7 @@ custom_ignores=""
43
54
 
44
55
  valid_languages="typescript rust python solidity"
45
56
  valid_features="ci codeql security test draft-pr release-pr release dependabot"
57
+ valid_profiles="auto application monorepo minimal"
46
58
  valid_release_types="auto node python rust simple none"
47
59
 
48
60
  contains_word() {
@@ -80,6 +92,7 @@ while [ "$#" -gt 0 ]; do
80
92
  case "$1" in
81
93
  --source) source="${2:?missing source path or URL}"; shift 2 ;;
82
94
  --ref) source_ref="${2:?missing ref}"; shift 2 ;;
95
+ --profile) profile="${2:?missing profile}"; profile_set=true; shift 2 ;;
83
96
  --languages) languages="${2:?missing language list}"; languages_set=true; shift 2 ;;
84
97
  --features) features="${2:?missing feature list}"; features_set=true; shift 2 ;;
85
98
  --package-manager) package_manager="${2:?missing package manager}"; package_manager_set=true; shift 2 ;;
@@ -93,6 +106,10 @@ done
93
106
 
94
107
  [ -n "$source" ] || { usage >&2; exit 2; }
95
108
  if [ -f .github/template.yml ]; then
109
+ if [ "$profile_set" = false ]; then
110
+ configured_profile="$(awk -F': ' '/^profile:/ {print $2; exit}' .github/template.yml)"
111
+ [ -n "$configured_profile" ] && profile="$configured_profile"
112
+ fi
96
113
  if [ "$languages_set" = false ]; then
97
114
  configured_languages="$(awk -F': ' '/^languages:/ {print $2; exit}' .github/template.yml)"
98
115
  [ -n "$configured_languages" ] && languages="$configured_languages"
@@ -105,10 +122,14 @@ if [ -f .github/template.yml ]; then
105
122
  package_manager="$(awk -F': ' '/^package_manager:/ {print $2; exit}' .github/template.yml)"
106
123
  fi
107
124
  template_ref="$(awk -F': ' '/^template:/ {print $2; exit}' .github/template.yml)"
108
- configured_release_type="$(awk -F': ' '/^release_type:/ {print $2; exit}' .github/template.yml)"
109
- configured_npm_publish="$(awk -F': ' '/^npm_publish:/ {print $2; exit}' .github/template.yml)"
110
- [ -n "$configured_release_type" ] && release_type="$configured_release_type"
111
- [ -n "$configured_npm_publish" ] && npm_publish="$configured_npm_publish"
125
+ if [ "$release_type_set" != true ]; then
126
+ configured_release_type="$(awk -F': ' '/^release_type:/ {print $2; exit}' .github/template.yml)"
127
+ [ -n "$configured_release_type" ] && release_type="$configured_release_type"
128
+ fi
129
+ if [ "$npm_publish_set" != true ]; then
130
+ configured_npm_publish="$(awk -F': ' '/^npm_publish:/ {print $2; exit}' .github/template.yml)"
131
+ [ -n "$configured_npm_publish" ] && npm_publish="$configured_npm_publish"
132
+ fi
112
133
  fi
113
134
  [ -n "$package_manager" ] || package_manager=auto
114
135
  case "$package_manager" in
@@ -117,6 +138,10 @@ case "$package_manager" in
117
138
  esac
118
139
  validate_list language "$languages" "$valid_languages"
119
140
  validate_list feature "$features" "$valid_features"
141
+ contains_word "$valid_profiles" "$profile" || {
142
+ printf 'Unsupported profile: %s\n' "$profile" >&2
143
+ exit 2
144
+ }
120
145
  contains_word "$valid_release_types" "$release_type" || {
121
146
  printf 'Unsupported release type: %s\n' "$release_type" >&2
122
147
  exit 2
@@ -131,6 +156,26 @@ else
131
156
  template_root="$temp_dir/template-repo"
132
157
  fi
133
158
 
159
+ # Resolve the effective profile after the template is available. This gives
160
+ # CLI flags and GitHub repository variables priority over template defaults,
161
+ # while making automatic detection concrete in the generated profile.
162
+ if [ -f "$template_root/.github/scripts/profile.sh" ]; then
163
+ profile_output="$(
164
+ REPO_FOUNDRY_PROFILE="$profile" \
165
+ REPO_FOUNDRY_LANGUAGES="$languages" \
166
+ REPO_FOUNDRY_FEATURES="$features" \
167
+ REPO_FOUNDRY_PACKAGE_MANAGER="$package_manager" \
168
+ REPO_FOUNDRY_RELEASE_TYPE="$release_type" \
169
+ REPO_FOUNDRY_NPM_PUBLISH="$npm_publish" \
170
+ bash "$template_root/.github/scripts/profile.sh" detect --root "$PWD"
171
+ )"
172
+ profile="$(printf '%s\n' "$profile_output" | awk -F= '$1 == "profile" {print substr($0, index($0, "=") + 1)}')"
173
+ languages="$(printf '%s\n' "$profile_output" | awk -F= '$1 == "languages" {print substr($0, index($0, "=") + 1)}')"
174
+ package_manager="$(printf '%s\n' "$profile_output" | awk -F= '$1 == "package_manager" {print substr($0, index($0, "=") + 1)}')"
175
+ release_type="$(printf '%s\n' "$profile_output" | awk -F= '$1 == "release_type" {print substr($0, index($0, "=") + 1)}')"
176
+ npm_publish="$(printf '%s\n' "$profile_output" | awk -F= '$1 == "npm_publish" {print substr($0, index($0, "=") + 1)}')"
177
+ fi
178
+
134
179
  if [ -f "$template_root/package.json" ]; then
135
180
  template_version="$(awk -F'"' '/"version"[[:space:]]*:/ {print $4; exit}' "$template_root/package.json")"
136
181
  [ -n "$template_version" ] && template_ref="code-foundry@$template_version"
@@ -160,6 +205,7 @@ files=(
160
205
  .github/actions/setup/action.yml
161
206
  .github/actions/cache/action.yml
162
207
  .github/actions/codeql/action.yml
208
+ .github/scripts/profile.sh
163
209
  .github/scripts/bootstrap.sh
164
210
  .github/scripts/changed-files.sh
165
211
  .github/scripts/ci.sh
@@ -404,6 +450,7 @@ if [ "$mode" = "apply" ]; then
404
450
  if [ -n "$template_ref" ]; then
405
451
  printf 'template: %s\n' "$template_ref"
406
452
  fi
453
+ printf 'profile: %s\n' "$profile"
407
454
  printf 'languages: %s\n' "$languages"
408
455
  printf 'features: %s\n' "$features"
409
456
  if [ -n "$package_manager" ]; then
@@ -1,7 +1,14 @@
1
1
  version: 1
2
2
  template: code-foundry@latest
3
+ profile: auto
3
4
  languages: typescript
4
5
  features: all
5
6
  package_manager: bun
6
7
  release_type: node
7
8
  npm_publish: true
9
+ runner: ubuntu-latest
10
+ unit_runner: ubuntu-slim
11
+ cache_packages: auto
12
+ cache_build: auto
13
+ coverage_minimum: 80
14
+ turbo_remote: auto
@@ -1,8 +1,15 @@
1
1
  # Repository-specific settings for the shared initializer and sync scripts.
2
2
  version: 1
3
3
  template: code-foundry@latest
4
+ profile: auto
4
5
  languages: auto
5
6
  features: all
6
7
  package_manager: auto
7
8
  release_type: auto
8
9
  npm_publish: false
10
+ runner: ubuntu-latest
11
+ unit_runner: ubuntu-slim
12
+ cache_packages: auto
13
+ cache_build: auto
14
+ coverage_minimum: 80
15
+ turbo_remote: auto
@@ -13,6 +13,13 @@ permissions:
13
13
  env:
14
14
  TURBO_TOKEN: ${{ secrets.TURBO_TOKEN }}
15
15
  TURBO_TEAM: ${{ vars.TURBO_TEAM }}
16
+ REPO_FOUNDRY_PROFILE: ${{ vars.REPO_FOUNDRY_PROFILE }}
17
+ REPO_FOUNDRY_LANGUAGES: ${{ vars.REPO_FOUNDRY_LANGUAGES }}
18
+ REPO_FOUNDRY_FEATURES: ${{ vars.REPO_FOUNDRY_FEATURES }}
19
+ REPO_FOUNDRY_PACKAGE_MANAGER: ${{ vars.REPO_FOUNDRY_PACKAGE_MANAGER }}
20
+ REPO_FOUNDRY_RUNNER: ${{ vars.REPO_FOUNDRY_RUNNER }}
21
+ REPO_FOUNDRY_CACHE_PACKAGES: ${{ vars.REPO_FOUNDRY_CACHE_PACKAGES || 'auto' }}
22
+ REPO_FOUNDRY_CACHE_BUILD: ${{ vars.REPO_FOUNDRY_CACHE_BUILD || 'auto' }}
16
23
  REPO_FOUNDRY_BASE_SHA: ${{ github.event_name == 'pull_request' && github.event.pull_request.base.sha || github.event.before || '' }}
17
24
 
18
25
  concurrency:
@@ -22,7 +29,7 @@ concurrency:
22
29
  jobs:
23
30
  format:
24
31
  name: Format
25
- runs-on: ${{ vars.REPO_FOUNDRY_FAST_RUNNER || 'ubuntu-latest' }}
32
+ runs-on: ${{ vars.REPO_FOUNDRY_RUNNER || vars.REPO_FOUNDRY_FAST_RUNNER || 'ubuntu-latest' }}
26
33
  timeout-minutes: 15
27
34
  steps:
28
35
  - name: Checkout
@@ -77,7 +84,7 @@ jobs:
77
84
 
78
85
  lint:
79
86
  name: Lint
80
- runs-on: ${{ vars.REPO_FOUNDRY_FAST_RUNNER || 'ubuntu-latest' }}
87
+ runs-on: ${{ vars.REPO_FOUNDRY_RUNNER || vars.REPO_FOUNDRY_FAST_RUNNER || 'ubuntu-latest' }}
81
88
  timeout-minutes: 20
82
89
  steps:
83
90
  - name: Checkout
@@ -15,6 +15,11 @@ permissions:
15
15
  packages: read
16
16
  security-events: write
17
17
 
18
+ env:
19
+ REPO_FOUNDRY_PROFILE: ${{ vars.REPO_FOUNDRY_PROFILE }}
20
+ REPO_FOUNDRY_LANGUAGES: ${{ vars.REPO_FOUNDRY_LANGUAGES }}
21
+ REPO_FOUNDRY_FEATURES: ${{ vars.REPO_FOUNDRY_FEATURES }}
22
+
18
23
  concurrency:
19
24
  group: ${{ github.workflow }}-${{ github.event.pull_request.head.repo.full_name || github.repository }}-${{ github.event.pull_request.head.ref || github.ref_name }}
20
25
  cancel-in-progress: true
@@ -23,7 +23,14 @@ jobs:
23
23
  - name: Check
24
24
  id: check-pr
25
25
  run: |
26
- EXISTING=$(gh pr list --limit 1 --base main --head staging --state open --json number 2>/dev/null | jq 'length')
26
+ set -euo pipefail
27
+ EXISTING=$(gh pr list \
28
+ --repo "$GITHUB_REPOSITORY" \
29
+ --limit 1 \
30
+ --base main \
31
+ --head staging \
32
+ --state open \
33
+ --json number | jq 'length')
27
34
  echo "existing=$EXISTING" >> "$GITHUB_OUTPUT"
28
35
 
29
36
  - name: Create
@@ -60,6 +67,7 @@ jobs:
60
67
  EOF
61
68
 
62
69
  gh pr create \
70
+ --repo "$GITHUB_REPOSITORY" \
63
71
  --base main \
64
72
  --head staging \
65
73
  --title "Release: staging -> main ($DATE)" \
@@ -10,6 +10,14 @@ permissions:
10
10
  issues: write
11
11
  pull-requests: write
12
12
 
13
+ env:
14
+ REPO_FOUNDRY_PROFILE: ${{ vars.REPO_FOUNDRY_PROFILE }}
15
+ REPO_FOUNDRY_LANGUAGES: ${{ vars.REPO_FOUNDRY_LANGUAGES }}
16
+ REPO_FOUNDRY_FEATURES: ${{ vars.REPO_FOUNDRY_FEATURES }}
17
+ REPO_FOUNDRY_PACKAGE_MANAGER: ${{ vars.REPO_FOUNDRY_PACKAGE_MANAGER }}
18
+ REPO_FOUNDRY_RELEASE_TYPE: ${{ vars.REPO_FOUNDRY_RELEASE_TYPE }}
19
+ REPO_FOUNDRY_NPM_PUBLISH: ${{ vars.REPO_FOUNDRY_NPM_PUBLISH }}
20
+
13
21
  jobs:
14
22
  release:
15
23
  name: Release / Version
@@ -33,8 +41,13 @@ jobs:
33
41
  id: profile
34
42
  shell: bash
35
43
  run: |
36
- release_type="$(awk -F': ' '/^release_type:/ {print $2; exit}' .github/template.yml 2>/dev/null || true)"
37
- npm_publish="$(awk -F': ' '/^npm_publish:/ {print $2; exit}' .github/template.yml 2>/dev/null || true)"
44
+ if [ -x .github/scripts/profile.sh ]; then
45
+ release_type="$(bash .github/scripts/profile.sh get release_type)"
46
+ npm_publish="$(bash .github/scripts/profile.sh get npm_publish)"
47
+ else
48
+ release_type="$(awk -F': ' '/^release_type:/ {print $2; exit}' .github/template.yml 2>/dev/null || true)"
49
+ npm_publish="$(awk -F': ' '/^npm_publish:/ {print $2; exit}' .github/template.yml 2>/dev/null || true)"
50
+ fi
38
51
  [ -n "$release_type" ] || release_type=auto
39
52
  [ -n "$npm_publish" ] || npm_publish=false
40
53
 
@@ -64,7 +77,6 @@ jobs:
64
77
  token: ${{ secrets.RELEASE_PLEASE_TOKEN || github.token }}
65
78
  config-file: release-please-config.json
66
79
  release-type: ${{ steps.profile.outputs.release_type }}
67
- bump-minor-pre-major: true
68
80
 
69
81
  npm:
70
82
  name: Release / Publish npm
@@ -11,6 +11,11 @@ permissions:
11
11
  contents: read
12
12
 
13
13
  env:
14
+ REPO_FOUNDRY_PROFILE: ${{ vars.REPO_FOUNDRY_PROFILE }}
15
+ REPO_FOUNDRY_LANGUAGES: ${{ vars.REPO_FOUNDRY_LANGUAGES }}
16
+ REPO_FOUNDRY_FEATURES: ${{ vars.REPO_FOUNDRY_FEATURES }}
17
+ REPO_FOUNDRY_PACKAGE_MANAGER: ${{ vars.REPO_FOUNDRY_PACKAGE_MANAGER }}
18
+ REPO_FOUNDRY_CACHE_PACKAGES: ${{ vars.REPO_FOUNDRY_CACHE_PACKAGES || 'auto' }}
14
19
  REPO_FOUNDRY_BASE_SHA: ${{ github.event_name == 'pull_request' && github.event.pull_request.base.sha || github.event.before || '' }}
15
20
 
16
21
  concurrency:
@@ -13,6 +13,12 @@ permissions:
13
13
  env:
14
14
  TURBO_TOKEN: ${{ secrets.TURBO_TOKEN }}
15
15
  TURBO_TEAM: ${{ vars.TURBO_TEAM }}
16
+ REPO_FOUNDRY_PROFILE: ${{ vars.REPO_FOUNDRY_PROFILE }}
17
+ REPO_FOUNDRY_LANGUAGES: ${{ vars.REPO_FOUNDRY_LANGUAGES }}
18
+ REPO_FOUNDRY_FEATURES: ${{ vars.REPO_FOUNDRY_FEATURES }}
19
+ REPO_FOUNDRY_PACKAGE_MANAGER: ${{ vars.REPO_FOUNDRY_PACKAGE_MANAGER }}
20
+ REPO_FOUNDRY_CACHE_PACKAGES: ${{ vars.REPO_FOUNDRY_CACHE_PACKAGES || 'auto' }}
21
+ REPO_FOUNDRY_CACHE_BUILD: ${{ vars.REPO_FOUNDRY_CACHE_BUILD || 'auto' }}
16
22
  REPO_FOUNDRY_BASE_SHA: ${{ github.event_name == 'pull_request' && github.event.pull_request.base.sha || github.event.before || '' }}
17
23
 
18
24
  concurrency:
package/CHANGELOG.md CHANGED
@@ -1,3 +1,12 @@
1
1
  # Changelog
2
2
 
3
+ ## [0.2.0](https://github.com/0xPlayerOne/code-foundry/compare/v0.1.4...v0.2.0) (2026-07-28)
4
+
5
+
6
+ ### Features
7
+
8
+ * document repository profile diagnostics ([29f132a](https://github.com/0xPlayerOne/code-foundry/commit/29f132a2b15053b06c7fe22c27324dc59151adee))
9
+
10
+ ## Changelog
11
+
3
12
  All notable changes to this project are documented here.
package/README.md CHANGED
@@ -44,7 +44,7 @@ bash .github/scripts/init-repo.sh
44
44
 
45
45
  Use `bash .github/scripts/sync-template.sh --source ... --check` to preview differences. For local template development, pass the template checkout as `--source` and `--ref staging`.
46
46
 
47
- The initializer is intentionally flag-driven so the same baseline can be used as a small repository package. Language selection controls CodeQL and records the repository profile; feature selection controls which standard workflows are installed. `auto` detects supported languages, while `all` enables every standard workflow.
47
+ The initializer is intentionally flag-driven so the same baseline can be used as a small repository package. Language selection controls CodeQL and records the repository profile; feature selection controls which standard workflows are installed. `auto` detects supported languages, while `all` enables every standard workflow. The resolver profiles the repository for language, package manager, project shape, release type, runners, and cache policy.
48
48
 
49
49
  ```bash
50
50
  # Preview a TypeScript + Python repository without changing files
@@ -59,7 +59,11 @@ bash .github/scripts/init-repo.sh \
59
59
  --features ci,codeql,security,test
60
60
  ```
61
61
 
62
- Supported languages are `typescript`, `rust`, `python`, and `solidity`. Supported feature flags are `ci`, `codeql`, `security`, `test`, `draft-pr`, `release-pr`, `release`, and `dependabot`. Use `--prune` only when you explicitly want disabled standard workflows removed; custom workflows are always preserved. The selected profile is stored in `.github/template.yml`, which makes later syncs repeatable and lets workflows consume repository-specific settings without duplicating the template scripts.
62
+ Supported profiles are `application`, `monorepo`, and `minimal`; use `auto` to detect one. Supported languages are `typescript`, `rust`, `python`, and `solidity`. Supported feature flags are `ci`, `codeql`, `security`, `test`, `draft-pr`, `release-pr`, `release`, and `dependabot`. Use `--prune` only when you explicitly want disabled standard workflows removed; custom workflows are always preserved. The selected profile is stored in `.github/template.yml`, which makes later syncs repeatable and lets workflows consume repository-specific settings without duplicating the template scripts.
63
+
64
+ Profile precedence is consistent everywhere: explicit CLI flags, then `REPO_FOUNDRY_*` GitHub repository variables/environment values, then `.github/template.yml`, then automatic detection and standard defaults. Useful repository variables include `REPO_FOUNDRY_PROFILE`, `REPO_FOUNDRY_LANGUAGES`, `REPO_FOUNDRY_FEATURES`, `REPO_FOUNDRY_PACKAGE_MANAGER`, `REPO_FOUNDRY_RUNNER`, `REPO_FOUNDRY_UNIT_RUNNER`, `REPO_FOUNDRY_CACHE_PACKAGES`, `REPO_FOUNDRY_CACHE_BUILD`, `REPO_FOUNDRY_COVERAGE_MINIMUM`, and `REPO_FOUNDRY_TURBO_REMOTE`. Use CLI flags for one-off initialization; use repository variables for local overrides that should not be committed.
65
+
66
+ Inspect the resolved profile at any time with `bash .github/scripts/profile.sh detect`; use `profile.sh get KEY` when another script needs one setting.
63
67
 
64
68
  ## Releases and publishing
65
69
 
package/package.json CHANGED
@@ -1,9 +1,17 @@
1
1
  {
2
2
  "name": "code-foundry",
3
- "version": "0.1.4",
3
+ "version": "0.2.0",
4
4
  "description": "A fast, language-aware repository factory for agent-ready workflows, testing, security, and release automation.",
5
5
  "type": "module",
6
6
  "license": "AGPL-3.0-or-later",
7
+ "repository": {
8
+ "type": "git",
9
+ "url": "https://github.com/0xPlayerOne/code-foundry.git"
10
+ },
11
+ "homepage": "https://github.com/0xPlayerOne/code-foundry#readme",
12
+ "bugs": {
13
+ "url": "https://github.com/0xPlayerOne/code-foundry/issues"
14
+ },
7
15
  "packageManager": "bun@1.3.14",
8
16
  "bin": {
9
17
  "code-foundry": "src/cli.mjs"
package/src/cli.mjs CHANGED
@@ -18,6 +18,7 @@ Init/sync options:
18
18
  --target PATH Repository directory (default: current directory)
19
19
  --source PATH_OR_URL Template source override
20
20
  --ref REF Template branch or tag (default: main)
21
+ --profile NAME auto, application, monorepo, or minimal
21
22
  --languages LIST auto or typescript,rust,python,solidity
22
23
  --features LIST all or ci,codeql,security,test,draft-pr,release-pr,release,dependabot
23
24
  --package-manager NAME auto, bun, pnpm, yarn, or npm
@@ -41,11 +42,12 @@ function parseArgs(argv) {
41
42
  target: process.cwd(),
42
43
  source: packageRoot,
43
44
  ref: 'main',
44
- languages: 'auto',
45
- features: 'all',
46
- packageManager: 'auto',
47
- releaseType: 'auto',
48
- npmPublish: false,
45
+ profile: process.env.REPO_FOUNDRY_PROFILE || 'auto',
46
+ languages: process.env.REPO_FOUNDRY_LANGUAGES || 'auto',
47
+ features: process.env.REPO_FOUNDRY_FEATURES || 'all',
48
+ packageManager: process.env.REPO_FOUNDRY_PACKAGE_MANAGER || 'auto',
49
+ releaseType: process.env.REPO_FOUNDRY_RELEASE_TYPE || 'auto',
50
+ npmPublish: process.env.REPO_FOUNDRY_NPM_PUBLISH === 'true',
49
51
  languagesSet: false,
50
52
  featuresSet: false,
51
53
  dryRun: false,
@@ -57,6 +59,7 @@ function parseArgs(argv) {
57
59
  ['--target', 'target'],
58
60
  ['--source', 'source'],
59
61
  ['--ref', 'ref'],
62
+ ['--profile', 'profile'],
60
63
  ['--languages', 'languages'],
61
64
  ['--features', 'features'],
62
65
  ['--package-manager', 'packageManager'],
@@ -114,6 +117,7 @@ function main() {
114
117
  const initArgs = [
115
118
  '--source', options.source,
116
119
  '--ref', options.ref,
120
+ '--profile', options.profile,
117
121
  '--languages', options.languages,
118
122
  '--features', options.features,
119
123
  '--package-manager', options.packageManager,