carson 2.13.3 → 2.14.1

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.
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: 17b8bd4f2f9f3b9d1cc1d637accc607cfb3f7a49e98cc4a998cb8b797a82bc50
4
- data.tar.gz: 3247d5bac41cbd0da539a45210521c66436b2ee3d2da8b6e28ee8f6a6c694955
3
+ metadata.gz: dad32a3bc4067fc3833f9ff468633f6167862dfbeadd229e085998a54887fba6
4
+ data.tar.gz: e3653cbe7da475a2f8a9439493481a91fb2737978a1206a5caa964019d3d9e80
5
5
  SHA512:
6
- metadata.gz: e018a857a0af89a3828355f0af131b4bf3fee40412d6c1e719c20493f9c6daf91f2da595d9b0b611f0df787a25e6d65997456668160615ca4b9c6419ffb89ee7
7
- data.tar.gz: f7db01059c1dfb0b8be6be61c34859c157ac7283df40f010120f57bcdc1ad95b3bbdaf2a6596329be260be1dfcb818d2b177ded70e92d637294441fe70bc0f69
6
+ metadata.gz: b1b3d0488e5410c1319c16c3e5c90577fc9d63307546c2a5c530f6d4af4898ce80f8b17978a7e50d17a6c16c17fdf3acedb35f27920127ef0c24086c0ca9b300
7
+ data.tar.gz: 3c37e91e582c39553732ed7f9ec002f72619f3b36213c9e77e87234636d68b62c141fd0b778c2e1b48e2f3d35555193cbfcd7d58b81761d2181113213761d08f
data/RELEASE.md CHANGED
@@ -5,6 +5,26 @@ Release-note scope rule:
5
5
  - `RELEASE.md` records only version deltas, breaking changes, and migration actions.
6
6
  - Operational usage guides live in `MANUAL.md` and `API.md`.
7
7
 
8
+ ## 2.14.1 — Auto-Refresh on Install
9
+
10
+ ### What changed
11
+
12
+ - `install.sh` now runs `carson refresh --all` automatically after linking the executable. Template changes (including superseded-file removal) are propagated to all governed repos the moment Carson is upgraded — no manual intervention required.
13
+ - If any repo reports issues, a warning is printed; the install itself does not fail.
14
+
15
+ ## 2.14.0 — Superseded File Cleanup on Template Apply
16
+
17
+ ### What changed
18
+
19
+ - `carson template apply` now automatically removes files that Carson previously managed but has since renamed or replaced. Running `carson template apply` in a governed repo after upgrading to 2.14.0 will delete `.github/carson-instructions.md` without any manual intervention.
20
+ - `carson template check` reports superseded files present in the repo as stale, listed with a `— superseded` annotation. Exit code `2` (BLOCK) if any stale files are detected.
21
+ - `offboard` also removes superseded files as part of full Carson cleanup.
22
+ - `carson.md` updated to reflect the new `template apply` behaviour.
23
+
24
+ ### No migration required
25
+
26
+ No manual steps needed. Run `carson template apply` — Carson handles the rest.
27
+
8
28
  ## 2.13.3 — Rename carson-instructions.md to carson.md
9
29
 
10
30
  ### What changed
data/VERSION CHANGED
@@ -1 +1 @@
1
- 2.13.3
1
+ 2.14.1
data/lib/carson/config.rb CHANGED
@@ -8,7 +8,7 @@ module Carson
8
8
  class Config
9
9
  attr_accessor :git_remote
10
10
  attr_reader :main_branch, :protected_branches, :hooks_base_path, :required_hooks,
11
- :path_groups, :template_managed_files,
11
+ :path_groups, :template_managed_files, :template_superseded_files,
12
12
  :lint_policy_source,
13
13
  :review_wait_seconds, :review_poll_seconds, :review_max_polls, :review_sweep_window_days,
14
14
  :review_sweep_states, :review_disposition_prefix, :review_risk_keywords,
@@ -48,7 +48,8 @@ module Carson
48
48
  }
49
49
  },
50
50
  "template" => {
51
- "managed_files" => [ ".github/carson.md", ".github/copilot-instructions.md", ".github/CLAUDE.md", ".github/AGENTS.md", ".github/pull_request_template.md", ".github/workflows/carson-lint.yml" ]
51
+ "managed_files" => [ ".github/carson.md", ".github/copilot-instructions.md", ".github/CLAUDE.md", ".github/AGENTS.md", ".github/pull_request_template.md", ".github/workflows/carson-lint.yml" ],
52
+ "superseded_files" => [ ".github/carson-instructions.md" ]
52
53
  },
53
54
  "lint" => {
54
55
  "policy_source" => "wanghailei/lint.git"
@@ -216,6 +217,7 @@ module Carson
216
217
  @path_groups = fetch_hash( hash: fetch_hash( hash: data, key: "scope" ), key: "path_groups" ).transform_values { |value| normalize_patterns( value: value ) }
217
218
 
218
219
  @template_managed_files = fetch_string_array( hash: fetch_hash( hash: data, key: "template" ), key: "managed_files" )
220
+ @template_superseded_files = fetch_optional_string_array( hash: fetch_hash( hash: data, key: "template" ), key: "superseded_files" )
219
221
  lint_hash = fetch_hash( hash: data, key: "lint" )
220
222
  @lint_policy_source = lint_hash.fetch( "policy_source", "" ).to_s.strip
221
223
 
@@ -339,27 +339,34 @@ module Carson
339
339
  puts_verbose ""
340
340
  puts_verbose "[Template Sync Check]"
341
341
  results = template_results
342
+ stale = template_superseded_present
342
343
  drift_count = results.count { |entry| entry.fetch( :status ) == "drift" }
343
344
  error_count = results.count { |entry| entry.fetch( :status ) == "error" }
345
+ stale_count = stale.count
344
346
  results.each do |entry|
345
347
  puts_verbose "template_file: #{entry.fetch( :file )} status=#{entry.fetch( :status )} reason=#{entry.fetch( :reason )}"
346
348
  end
347
- puts_verbose "template_summary: total=#{results.count} drift=#{drift_count} error=#{error_count}"
349
+ stale.each { |file| puts_verbose "template_file: #{file} status=stale reason=superseded" }
350
+ puts_verbose "template_summary: total=#{results.count} drift=#{drift_count} stale=#{stale_count} error=#{error_count}"
348
351
  unless verbose?
349
- if drift_count.positive?
350
- drift_files = results.select { |entry| entry.fetch( :status ) == "drift" }.map { |entry| entry.fetch( :file ) }
351
- puts_line "Templates: #{drift_count} of #{results.count} drifted"
352
- drift_files.each { |file| puts_line " #{file}" }
352
+ if ( drift_count + stale_count ).positive?
353
+ summary_parts = []
354
+ summary_parts << "#{drift_count} of #{results.count} drifted" if drift_count.positive?
355
+ summary_parts << "#{stale_count} stale" if stale_count.positive?
356
+ puts_line "Templates: #{summary_parts.join( ", " )}"
357
+ results.select { |entry| entry.fetch( :status ) == "drift" }.each { |entry| puts_line " #{entry.fetch( :file )}" }
358
+ stale.each { |file| puts_line " #{file} — superseded" }
353
359
  else
354
360
  puts_line "Templates: #{results.count} files in sync"
355
361
  end
356
362
  end
357
363
  return EXIT_ERROR if error_count.positive?
358
364
 
359
- drift_count.positive? ? EXIT_BLOCK : EXIT_OK
365
+ ( drift_count + stale_count ).positive? ? EXIT_BLOCK : EXIT_OK
360
366
  end
361
367
 
362
368
  # Applies managed template files as full-file writes from Carson sources.
369
+ # Also removes superseded files that are no longer part of the managed set.
363
370
  def template_apply!
364
371
  fingerprint_status = block_if_outsider_fingerprints!
365
372
  return fingerprint_status unless fingerprint_status.nil?
@@ -367,6 +374,7 @@ module Carson
367
374
  puts_verbose ""
368
375
  puts_verbose "[Template Sync Apply]"
369
376
  results = template_results
377
+ stale = template_superseded_present
370
378
  applied = 0
371
379
  results.each do |entry|
372
380
  if entry.fetch( :status ) == "error"
@@ -386,11 +394,22 @@ module Carson
386
394
  applied += 1
387
395
  end
388
396
 
397
+ removed = 0
398
+ stale.each do |file|
399
+ file_path = resolve_repo_path!( relative_path: file, label: "template.superseded_files entry #{file}" )
400
+ File.delete( file_path )
401
+ puts_verbose "template_file: #{file} status=removed reason=superseded"
402
+ removed += 1
403
+ end
404
+
389
405
  error_count = results.count { |entry| entry.fetch( :status ) == "error" }
390
- puts_verbose "template_apply_summary: updated=#{applied} error=#{error_count}"
406
+ puts_verbose "template_apply_summary: updated=#{applied} removed=#{removed} error=#{error_count}"
391
407
  unless verbose?
392
- if applied.positive?
393
- puts_line "Templates applied (#{applied} updated)."
408
+ if applied.positive? || removed.positive?
409
+ summary_parts = []
410
+ summary_parts << "#{applied} updated" if applied.positive?
411
+ summary_parts << "#{removed} removed" if removed.positive?
412
+ puts_line "Templates applied (#{summary_parts.join( ", " )})."
394
413
  else
395
414
  puts_line "Templates in sync."
396
415
  end
@@ -428,6 +447,13 @@ module Carson
428
447
  config.template_managed_files.map { |managed_file| template_result_for_file( managed_file: managed_file ) }
429
448
  end
430
449
 
450
+ def template_superseded_present
451
+ config.template_superseded_files.select do |file|
452
+ file_path = resolve_repo_path!( relative_path: file, label: "template.superseded_files entry #{file}" )
453
+ File.file?( file_path )
454
+ end
455
+ end
456
+
431
457
  # Calculates whole-file expected content and returns sync status plus apply payload.
432
458
  def template_result_for_file( managed_file: )
433
459
  # Try subdirectory-aware path first (e.g. .github/workflows/carson-lint.yml),
@@ -764,7 +790,7 @@ module Carson
764
790
  end
765
791
 
766
792
  def offboard_cleanup_targets
767
- ( config.template_managed_files + [
793
+ ( config.template_managed_files + config.template_superseded_files + [
768
794
  ".github/workflows/carson-governance.yml",
769
795
  ".github/workflows/carson_policy.yml",
770
796
  ".carson.yml",
@@ -11,8 +11,8 @@ Carson has no `commit`, `push`, or `pr` commands. Use `git` and `gh` for those.
11
11
  **Before committing:**
12
12
  ```bash
13
13
  carson audit # full governance check — run before every commit
14
- carson template check # detect drift in .github/* managed files
15
- carson template apply # fix drift if detected
14
+ carson template check # detect drift in .github/* managed files, including stale superseded files
15
+ carson template apply # fix drift and remove superseded files
16
16
  ```
17
17
 
18
18
  **Before recommending merge:**
metadata CHANGED
@@ -1,7 +1,7 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: carson
3
3
  version: !ruby/object:Gem::Version
4
- version: 2.13.3
4
+ version: 2.14.1
5
5
  platform: ruby
6
6
  authors:
7
7
  - Hailei Wang