Class: NitroKit::Installation

Inherits:
Object
  • Object
show all
Defined in:
lib/nitro_kit/installation.rb

Defined Under Namespace

Classes: Check, LayoutAnalysis, LayoutExpression

Constant Summary collapse

ROOT =
Pathname.new(File.expand_path("../..", __dir__))
SKILLS =
%w[nitro-kit-hotwire nitro-kit-rails nitro-kit-ui].freeze
SKILL_ROOTS =
[ ".agents/skills", ".claude/skills" ].freeze
MANAGED_STYLESHEETS =
%w[
  lexxy nitro_kit-tailwind-v4 nitro_kit tailwind application
].freeze
AGENTS_START =
"<!-- nitro-kit:start -->"
AGENTS_END =
"<!-- nitro-kit:end -->"
AGENTS_BLOCK =
<<~MARKDOWN.freeze
  #{AGENTS_START}
  ## Nitro Kit 2

  This application uses Nitro Kit 2.x. Before changing Rails structure,
  Hotwire interactions, or UI, use the matching project-local Nitro Kit skill.
  Each skill resolves the installed gem with `bundle show nitro_kit` and reads
  its version-matched documentation.

  Do not use Nitro Kit 1.x APIs, `nk_*` helpers, copied Nitro components, or
  application-owned `controllers/nk`. Compose the installed Phlex Kit and keep
  routes, records, authorization, queries, DOM IDs, and server responses in the
  application.

  During migration, replace an existing form control only when Nitro Kit 2 has
  a genuine semantic and behavioral equivalent. Otherwise preserve the control
  as application-owned Rails and semantic HTML. Never downgrade specialized
  behavior or retain copied Nitro Kit 1.x source as the fallback.
  #{AGENTS_END}
MARKDOWN

Instance Attribute Summary collapse

Instance Method Summary collapse

Constructor Details

#initialize(application_root) ⇒ Installation

Returns a new instance of Installation.



44
45
46
# File 'lib/nitro_kit/installation.rb', line 44

def initialize(application_root)
  @application_root = Pathname.new(application_root)
end

Instance Attribute Details

#application_rootObject (readonly)

Returns the value of attribute application_root.



42
43
44
# File 'lib/nitro_kit/installation.rb', line 42

def application_root
  @application_root
end

Instance Method Details

#checksObject



88
89
90
91
92
93
94
95
96
97
98
99
# File 'lib/nitro_kit/installation.rb', line 88

def checks
  [
    version_check,
    agents_check,
    skills_check,
    hotwire_check,
    stimulus_loader_check,
    stylesheet_setup_check,
    phlex_kit_check,
    *migration_checks
  ]
end

#copy_promptObject



78
79
80
81
82
83
84
85
86
# File 'lib/nitro_kit/installation.rb', line 78

def copy_prompt
  command = clipboard_command
  raise "No supported clipboard command found" unless command

  IO.popen(command, "w") { _1.write(prompt) }
  raise "Clipboard command failed" unless $?.success?

  command.first
end

#healthy?Boolean

Returns:

  • (Boolean)


101
102
103
# File 'lib/nitro_kit/installation.rb', line 101

def healthy?
  checks.none? { _1.status == :fail }
end

#installObject



48
49
50
51
52
# File 'lib/nitro_kit/installation.rb', line 48

def install
  changes = { "AGENTS.md" => write_agents }.merge(write_skills)
  changes[relative(layout_path)] = write_layout if layout_path
  changes
end

#promptObject



74
75
76
# File 'lib/nitro_kit/installation.rb', line 74

def prompt
  ROOT.join("docs/initialization_prompt.md").read
end

#write_agentsObject



54
55
56
57
58
59
60
61
62
63
64
# File 'lib/nitro_kit/installation.rb', line 54

def write_agents
  path = application_root.join("AGENTS.md")
  current = path.exist? ? path.read : ""
  updated = if current.include?(AGENTS_START)
    current.sub(/#{Regexp.escape(AGENTS_START)}.*?#{Regexp.escape(AGENTS_END)}/m, AGENTS_BLOCK.rstrip)
  else
    [ current.rstrip, AGENTS_BLOCK.rstrip ].reject(&:empty?).join("\n\n")
  end

  write(path, "#{updated.rstrip}\n")
end

#write_skillsObject



66
67
68
69
70
71
72
# File 'lib/nitro_kit/installation.rb', line 66

def write_skills
  SKILL_ROOTS.product(SKILLS).to_h do |root, skill|
    destination = application_root.join(root, skill, "SKILL.md")
    source = skill_source(skill)
    [ destination.relative_path_from(application_root).to_s, write(destination, source.read) ]
  end
end