Class: RailsAiBridge::Serializers::ContextFileSerializer

Inherits:
Object
  • Object
show all
Defined in:
lib/rails_ai_bridge/serializers/context_file_serializer.rb

Overview

Orchestrates writing context files to disk in various formats. Supports: CLAUDE.md, .cursorrules, .devinrules, .github/copilot-instructions.md, JSON Also generates split rule files for AI tools that support them.

Constant Summary collapse

FORMAT_MAP =
{
  claude: 'CLAUDE.md',
  codex: 'AGENTS.md',
  cursor: '.cursorrules',
  devin: '.devinrules',
  copilot: '.github/copilot-instructions.md',
  json: '.ai-context.json',
  gemini: 'GEMINI.md'
}.freeze
VALID_ON_CONFLICT_SYMBOLS =
%i[overwrite skip prompt].freeze
UNMANAGEABLE_FORMATS =

Managed regions are markdown-comment delimited, so JSON output never participates.

%i[json].freeze
DEFAULT_WRITE_OPTIONS =

Defaults applied when the caller omits the corresponding write option.

{
  format: :all,
  split_rules: true,
  on_conflict: :overwrite,
  managed_region: nil
}.freeze

Instance Attribute Summary collapse

Instance Method Summary collapse

Constructor Details

#initialize(context, fingerprint:, **write_options) ⇒ ContextFileSerializer

Returns a new instance of ContextFileSerializer.

Parameters:

  • context (Hash) —

    introspection context from RailsAiBridge.introspect

  • fingerprint (String) —

    12-char source fingerprint computed by the caller with Fingerprinter.source_fingerprint(app) (required)

  • write_options (Hash) —

    optional write options, merged over DEFAULT_WRITE_OPTIONS

Options Hash (**write_options):

  • :format (Symbol, Array<Symbol>) —

    format(s) to generate (default :all)

  • :split_rules (Boolean) —

    whether to generate per-assistant rule directories (default true)

  • :on_conflict (:overwrite, :skip, :prompt, #call) —

    conflict resolution strategy; any object responding to :call is invoked with the filepath and must return a truthy value to allow overwriting (default :overwrite)

  • :managed_region (Boolean, nil) —

    confine generated output to a marked region so hand-authored content in the file survives; nil inherits config.output.managed_region (default nil)

Raises:

  • (ArgumentError) —

    when on_conflict is not a recognised symbol or callable, when fingerprint is nil or empty, or when an unknown write option key is given



50
51
52
53
54
55
56
57
58
59
60
61
62
63
# File 'lib/rails_ai_bridge/serializers/context_file_serializer.rb', line 50

def initialize(context, fingerprint:, **write_options)
  unknown = write_options.keys - DEFAULT_WRITE_OPTIONS.keys
  raise ArgumentError, "Unknown write option(s): #{unknown.join(', ')}" unless unknown.empty?
  raise ArgumentError, 'fingerprint: is required; compute it with Fingerprinter.source_fingerprint(AppScope.current_app)' if !fingerprint || fingerprint.to_s.empty?

  options = DEFAULT_WRITE_OPTIONS.merge(write_options)
  @context     = context
  @format      = options[:format]
  @split_rules = options[:split_rules]
  @conflict_policy = ConflictPolicy.build(options[:on_conflict])
  @fingerprint = fingerprint
  managed_region = options[:managed_region]
  @managed_region = managed_region.nil? ? RailsAiBridge.configuration.managed_region : managed_region
end

Instance Attribute Details

#context ⇒ Object (readonly)

Returns the value of attribute context.



9
10
11
# File 'lib/rails_ai_bridge/serializers/context_file_serializer.rb', line 9

def context
  @context
end

#format ⇒ Object (readonly)

Returns the value of attribute format.



9
10
11
# File 'lib/rails_ai_bridge/serializers/context_file_serializer.rb', line 9

def format
  @format
end

#split_rules ⇒ Object (readonly)

Returns the value of attribute split_rules.



9
10
11
# File 'lib/rails_ai_bridge/serializers/context_file_serializer.rb', line 9

def split_rules
  @split_rules
end

Instance Method Details

#call ⇒ Hash{Symbol => Array<String>}

Write context files to the configured output directory, skipping unchanged ones.

Returns:

  • (Hash{Symbol => Array<String>}) —

    :written paths and :skipped paths

Raises:

  • (ArgumentError) —

    when an unrecognised format symbol is encountered



69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
# File 'lib/rails_ai_bridge/serializers/context_file_serializer.rb', line 69

def call
  formats = format == :all ? FORMAT_MAP.keys : Array(format)
  output_dir = RailsAiBridge.configuration.output_dir_for(AppScope.current_app)
  written = []
  skipped = []

  timestamp_now = Time.now.utc.iso8601

  formats.each do |fmt|
    process_format(fmt, output_dir, timestamp_now, @fingerprint, written, skipped)
  end

  generate_split_rules(formats, output_dir, written, skipped) if split_rules

  { written: written, skipped: skipped }
end