Class: Ace::PromptPrep::Molecules::PromptArchiver

Inherits:
Object
  • Object
show all
Defined in:
lib/ace/prompt_prep/molecules/prompt_archiver.rb

Overview

Archives prompt file with timestamp and updates symlink

Constant Summary collapse

DEFAULT_CACHE_DIR =

Default directories (fallback if config unavailable)

Ace::PromptPrep::Defaults::DEFAULT_CACHE_DIR
DEFAULT_ARCHIVE_DIR =
"prompts/archive"
"prompts/_previous.md"

Class Method Summary collapse

Class Method Details

.archive_dir_from_configString

Get archive directory from config

Returns:

  • (String)

    Archive directory relative to project root



19
20
21
22
23
24
# File 'lib/ace/prompt_prep/molecules/prompt_archiver.rb', line 19

def self.archive_dir_from_config
  config = Ace::PromptPrep.config
  cache_dir = config.dig("paths", "cache_dir") || DEFAULT_CACHE_DIR
  archive_dir = config.dig("paths", "archive_dir") || DEFAULT_ARCHIVE_DIR
  File.join(cache_dir, archive_dir)
end

.call(content:, timestamp: nil, archive_dir: nil, symlink_path: nil) ⇒ Hash

Archive prompt content

Parameters:

  • content (String)

    Content to archive

  • timestamp (String, nil) (defaults to: nil)

    Optional timestamp (default: generated)

  • archive_dir (String, nil) (defaults to: nil)

    Optional custom archive directory

  • symlink_path (String, nil) (defaults to: nil)

    Optional custom symlink path

Returns:

  • (Hash)

    Hash with :archive_path, :symlink_path, :success, :error keys



42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
# File 'lib/ace/prompt_prep/molecules/prompt_archiver.rb', line 42

def self.call(content:, timestamp: nil, archive_dir: nil, symlink_path: nil)
  return {success: false, error: "Error: Content to archive cannot be nil"} if content.nil?

  project_root = Ace::Support::Fs::Molecules::ProjectRootFinder.find_or_current
  archive_dir ||= File.join(project_root, archive_dir_from_config)
  FileUtils.mkdir_p(archive_dir)

  # Generate or use provided timestamp
  ts = timestamp || Atoms::SessionIdGenerator.call[:timestamp]

  # Handle timestamp collision by appending suffix
  archive_filename = "#{ts}.md"
  archive_path = File.join(archive_dir, archive_filename)
  counter = 1
  while File.exist?(archive_path)
    archive_filename = "#{ts}-#{counter}.md"
    archive_path = File.join(archive_dir, archive_filename)
    counter += 1
  end

  # Write archive file
  File.write(archive_path, content, encoding: "utf-8")

  # Update symlink
  symlink_path ||= File.join(project_root, previous_symlink_from_config)
  update_symlink_result = update_symlink(symlink_path, archive_path)

  {
    archive_path: archive_path,
    symlink_path: symlink_path,
    symlink_updated: update_symlink_result[:success],
    success: true,
    error: nil
  }
rescue => e
  {
    archive_path: nil,
    symlink_path: nil,
    success: false,
    error: "Error: Failed to archive file: #{e.message}"
  }
end

Get previous symlink path from config

Returns:

  • (String)

    Previous symlink path relative to project root



28
29
30
31
32
33
# File 'lib/ace/prompt_prep/molecules/prompt_archiver.rb', line 28

def self.previous_symlink_from_config
  config = Ace::PromptPrep.config
  cache_dir = config.dig("paths", "cache_dir") || DEFAULT_CACHE_DIR
  previous_symlink = config.dig("paths", "previous_symlink") || DEFAULT_PREVIOUS_SYMLINK
  File.join(cache_dir, previous_symlink)
end

Update symlink to point to archive file

Parameters:

  • symlink_path (String)

    Path to symlink

  • target_path (String)

    Path to target file

Returns:

  • (Hash)

    Hash with :success, :error keys



90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
# File 'lib/ace/prompt_prep/molecules/prompt_archiver.rb', line 90

def self.update_symlink(symlink_path, target_path)
  # Remove existing symlink if it exists
  File.delete(symlink_path) if File.exist?(symlink_path) || File.symlink?(symlink_path)

  # Create relative path from symlink to target
  # Both are in .ace-local/prompt-prep/prompts/, target is in archive/ subdirectory
  target_basename = File.basename(target_path)
  relative_target = "archive/#{target_basename}"

  # Create new symlink
  File.symlink(relative_target, symlink_path)

  {success: true, error: nil}
rescue => e
  {success: false, error: "Error: Failed to update symlink: #{e.message}"}
end