context_spook 1.1.0 → 1.3.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.
- checksums.yaml +4 -4
- data/Rakefile +1 -0
- data/bin/context_spook +11 -6
- data/context_spook.gemspec +7 -6
- data/lib/context_spook/generator.rb +19 -45
- data/lib/context_spook/output_context.rb +36 -0
- data/lib/context_spook/toon.rb +20 -0
- data/lib/context_spook/utils.rb +19 -0
- data/lib/context_spook/verbose_puts.rb +25 -0
- data/lib/context_spook/version.rb +1 -1
- data/lib/context_spook.rb +1 -0
- data/spec/context_spook/generator_spec.rb +78 -42
- data/spec/context_spook/toon_spec.rb +56 -0
- metadata +27 -3
checksums.yaml
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
---
|
|
2
2
|
SHA256:
|
|
3
|
-
metadata.gz:
|
|
4
|
-
data.tar.gz:
|
|
3
|
+
metadata.gz: a00a3e36535b351b630e539a1dfae938bb2325c2f639e3d0b318f1cac0e8c14f
|
|
4
|
+
data.tar.gz: 3c7976d1672dd67d6b0b07d64350e3baf211d6e8752b83631de9f5a17ae642f3
|
|
5
5
|
SHA512:
|
|
6
|
-
metadata.gz:
|
|
7
|
-
data.tar.gz:
|
|
6
|
+
metadata.gz: 82bf0afffa28eab0b379ec94c9a7a7cd34406ca82ccf4a7e78d26103082b8610ce3461a06a26772381fe59d6cfa401516eed532d33c6742cff980d08dea5508d
|
|
7
|
+
data.tar.gz: f969059b0b7ca9490ceb6560c5735da343c4ee5ee5ff856bae919da5ab66f02886e55a7096ad33b91241a147d78f5b5a82ec652ce25800658d46e4dc6a87bbc2
|
data/Rakefile
CHANGED
|
@@ -38,6 +38,7 @@ GemHadar do
|
|
|
38
38
|
dependency 'mime-types', '~> 3.0'
|
|
39
39
|
dependency 'yaml', '~> 0.4'
|
|
40
40
|
dependency 'pathname', '~> 0.4'
|
|
41
|
+
dependency 'ruby-json-toon', '~> 1.0'
|
|
41
42
|
development_dependency 'all_images', '~> 0.6'
|
|
42
43
|
development_dependency 'rspec', '~> 3.2'
|
|
43
44
|
development_dependency 'debug'
|
data/bin/context_spook
CHANGED
|
@@ -26,6 +26,7 @@ def usage
|
|
|
26
26
|
-S suppress output (just show informational output)
|
|
27
27
|
-i PATTERN Include files matching PATTERN (can be used multiple times)
|
|
28
28
|
Supports glob patterns like **, *, ?, [abc], {a,b,c}
|
|
29
|
+
-F FORMAT Output context as format JSON (the default) or TOON
|
|
29
30
|
-h Show this help message
|
|
30
31
|
|
|
31
32
|
Examples:
|
|
@@ -54,13 +55,13 @@ def usage
|
|
|
54
55
|
exit 0
|
|
55
56
|
end
|
|
56
57
|
|
|
57
|
-
opts = go 'o:i:pvSh', defaults: { ?v => true }
|
|
58
|
+
opts = go 'o:i:F:pvSh', defaults: { ?v => true }
|
|
58
59
|
opts[?h] and usage
|
|
59
60
|
context = nil
|
|
60
61
|
output = nil
|
|
61
62
|
|
|
62
63
|
if opts[?i]
|
|
63
|
-
context = ContextSpook.generate_context(verbose: opts[?v]) do
|
|
64
|
+
context = ContextSpook.generate_context(verbose: opts[?v], format: opts[?F]) do
|
|
64
65
|
context do
|
|
65
66
|
opts[?i].to_a.each do |glob|
|
|
66
67
|
glob = File.expand_path(glob)
|
|
@@ -73,9 +74,10 @@ if opts[?i]
|
|
|
73
74
|
end
|
|
74
75
|
else
|
|
75
76
|
filename = ARGV.shift or fail 'require context definition file as an argument'
|
|
76
|
-
context = ContextSpook.generate_context(filename, verbose: opts[?v])
|
|
77
|
+
context = ContextSpook.generate_context(filename, verbose: opts[?v], format: opts[?F])
|
|
77
78
|
end
|
|
78
79
|
|
|
80
|
+
output = STDOUT
|
|
79
81
|
if opts[?S]
|
|
80
82
|
output = NULL
|
|
81
83
|
else
|
|
@@ -84,8 +86,11 @@ else
|
|
|
84
86
|
fail "Filename #{output_filename.inspect} already exists!"
|
|
85
87
|
end
|
|
86
88
|
output = File.new output_filename, ?w
|
|
87
|
-
else
|
|
88
|
-
output = STDOUT
|
|
89
89
|
end
|
|
90
90
|
end
|
|
91
|
-
|
|
91
|
+
case opts[?F]
|
|
92
|
+
when /\A(JSON|TOON)\z/i, nil
|
|
93
|
+
context.generator.output_context(output:)
|
|
94
|
+
else
|
|
95
|
+
STDERR.puts "Invalid output format #{opts[?F].inspect}"
|
|
96
|
+
end
|
data/context_spook.gemspec
CHANGED
|
@@ -1,9 +1,9 @@
|
|
|
1
1
|
# -*- encoding: utf-8 -*-
|
|
2
|
-
# stub: context_spook 1.
|
|
2
|
+
# stub: context_spook 1.3.0 ruby lib
|
|
3
3
|
|
|
4
4
|
Gem::Specification.new do |s|
|
|
5
5
|
s.name = "context_spook".freeze
|
|
6
|
-
s.version = "1.
|
|
6
|
+
s.version = "1.3.0".freeze
|
|
7
7
|
|
|
8
8
|
s.required_rubygems_version = Gem::Requirement.new(">= 0".freeze) if s.respond_to? :required_rubygems_version=
|
|
9
9
|
s.require_paths = ["lib".freeze]
|
|
@@ -12,19 +12,19 @@ Gem::Specification.new do |s|
|
|
|
12
12
|
s.description = "context_spook is a library that collects and organizes project\ninformation to help AI assistants understand codebases better.\n".freeze
|
|
13
13
|
s.email = "flori@ping.de".freeze
|
|
14
14
|
s.executables = ["context_spook".freeze]
|
|
15
|
-
s.extra_rdoc_files = ["README.md".freeze, "lib/context_spook.rb".freeze, "lib/context_spook/generator.rb".freeze, "lib/context_spook/version.rb".freeze]
|
|
16
|
-
s.files = [".contexts/project.rb".freeze, "Gemfile".freeze, "LICENSE".freeze, "README.md".freeze, "Rakefile".freeze, "bin/context_spook".freeze, "context_spook.gemspec".freeze, "hello_world.json".freeze, "hey_world.yaml".freeze, "lib/context_spook.rb".freeze, "lib/context_spook/generator.rb".freeze, "lib/context_spook/version.rb".freeze, "spec/context_spook/generator_spec.rb".freeze, "spec/spec_helper.rb".freeze]
|
|
15
|
+
s.extra_rdoc_files = ["README.md".freeze, "lib/context_spook.rb".freeze, "lib/context_spook/generator.rb".freeze, "lib/context_spook/output_context.rb".freeze, "lib/context_spook/toon.rb".freeze, "lib/context_spook/utils.rb".freeze, "lib/context_spook/verbose_puts.rb".freeze, "lib/context_spook/version.rb".freeze]
|
|
16
|
+
s.files = [".contexts/project.rb".freeze, "Gemfile".freeze, "LICENSE".freeze, "README.md".freeze, "Rakefile".freeze, "bin/context_spook".freeze, "context_spook.gemspec".freeze, "hello_world.json".freeze, "hey_world.yaml".freeze, "lib/context_spook.rb".freeze, "lib/context_spook/generator.rb".freeze, "lib/context_spook/output_context.rb".freeze, "lib/context_spook/toon.rb".freeze, "lib/context_spook/utils.rb".freeze, "lib/context_spook/verbose_puts.rb".freeze, "lib/context_spook/version.rb".freeze, "spec/context_spook/generator_spec.rb".freeze, "spec/context_spook/toon_spec.rb".freeze, "spec/spec_helper.rb".freeze]
|
|
17
17
|
s.homepage = "https://github.com/flori/context_spook".freeze
|
|
18
18
|
s.licenses = ["MIT".freeze]
|
|
19
19
|
s.rdoc_options = ["--title".freeze, "ContextSpook - context_spook collects project context for AI".freeze, "--main".freeze, "README.md".freeze]
|
|
20
20
|
s.required_ruby_version = Gem::Requirement.new(">= 3.1".freeze)
|
|
21
21
|
s.rubygems_version = "4.0.3".freeze
|
|
22
22
|
s.summary = "context_spook collects project context for AI".freeze
|
|
23
|
-
s.test_files = ["spec/context_spook/generator_spec.rb".freeze, "spec/spec_helper.rb".freeze]
|
|
23
|
+
s.test_files = ["spec/context_spook/generator_spec.rb".freeze, "spec/context_spook/toon_spec.rb".freeze, "spec/spec_helper.rb".freeze]
|
|
24
24
|
|
|
25
25
|
s.specification_version = 4
|
|
26
26
|
|
|
27
|
-
s.add_development_dependency(%q<gem_hadar>.freeze, [">= 2.
|
|
27
|
+
s.add_development_dependency(%q<gem_hadar>.freeze, [">= 2.17.0".freeze])
|
|
28
28
|
s.add_development_dependency(%q<all_images>.freeze, ["~> 0.6".freeze])
|
|
29
29
|
s.add_development_dependency(%q<rspec>.freeze, ["~> 3.2".freeze])
|
|
30
30
|
s.add_development_dependency(%q<debug>.freeze, [">= 0".freeze])
|
|
@@ -36,4 +36,5 @@ Gem::Specification.new do |s|
|
|
|
36
36
|
s.add_runtime_dependency(%q<mime-types>.freeze, ["~> 3.0".freeze])
|
|
37
37
|
s.add_runtime_dependency(%q<yaml>.freeze, ["~> 0.4".freeze])
|
|
38
38
|
s.add_runtime_dependency(%q<pathname>.freeze, ["~> 0.4".freeze])
|
|
39
|
+
s.add_runtime_dependency(%q<ruby-json-toon>.freeze, ["~> 1.0".freeze])
|
|
39
40
|
end
|
|
@@ -4,36 +4,15 @@ require 'json'
|
|
|
4
4
|
require 'mize'
|
|
5
5
|
require 'mime-types'
|
|
6
6
|
require 'yaml'
|
|
7
|
+
require 'context_spook/toon'
|
|
8
|
+
require 'context_spook/verbose_puts'
|
|
9
|
+
require 'context_spook/output_context'
|
|
7
10
|
|
|
8
11
|
# The ContextSpook module serves as a namespace container for collecting and
|
|
9
12
|
# organizing project information for AI assistance.
|
|
10
13
|
module ContextSpook
|
|
11
14
|
include DSLKit::Interpreter
|
|
12
15
|
|
|
13
|
-
# The VerbosePuts module provides a conditional output mechanism for
|
|
14
|
-
# displaying status or debug messages.
|
|
15
|
-
#
|
|
16
|
-
# This module includes a method that outputs messages to standard error only
|
|
17
|
-
# when a verbose flag is enabled. It is designed to be included in classes
|
|
18
|
-
# that need to conditionally emit verbose logging information during
|
|
19
|
-
# processing.
|
|
20
|
-
module VerbosePuts
|
|
21
|
-
# The verbose_puts method outputs the given arguments to standard error
|
|
22
|
-
# only if verbose mode is enabled.
|
|
23
|
-
#
|
|
24
|
-
# This method serves as a conditional output mechanism, allowing debug or
|
|
25
|
-
# status messages to be displayed based on the verbosity setting of the
|
|
26
|
-
# object.
|
|
27
|
-
#
|
|
28
|
-
# @param a [ Array ] the arguments to be printed to standard error
|
|
29
|
-
#
|
|
30
|
-
# @return [ nil ] always returns nil after attempting to output
|
|
31
|
-
def verbose_puts(*a)
|
|
32
|
-
@verbose or return
|
|
33
|
-
STDERR.puts(a)
|
|
34
|
-
end
|
|
35
|
-
end
|
|
36
|
-
|
|
37
16
|
# The generate_context method processes a context definition file or block
|
|
38
17
|
# and returns the resulting context object.
|
|
39
18
|
#
|
|
@@ -56,14 +35,14 @@ module ContextSpook
|
|
|
56
35
|
#
|
|
57
36
|
# @raise [ ArgumentError ] if neither a filename nor a block is provided
|
|
58
37
|
# @raise [ ArgumentError ] if both a filename and a block are provided
|
|
59
|
-
def self.generate_context(filename = nil, verbose: false, &block)
|
|
38
|
+
def self.generate_context(filename = nil, verbose: false, format: nil, &block)
|
|
60
39
|
verbose = !!verbose
|
|
61
40
|
filename.present? ^ block or
|
|
62
41
|
raise ArgumentError, 'need either a filename or a &block argument'
|
|
63
42
|
generator = if filename
|
|
64
|
-
Generator.send(:new, verbose:).send(:parse, File.read(filename))
|
|
43
|
+
Generator.send(:new, verbose:, format:).send(:parse, File.read(filename))
|
|
65
44
|
else
|
|
66
|
-
Generator.send(:new, verbose:, &block)
|
|
45
|
+
Generator.send(:new, verbose:, format:, &block)
|
|
67
46
|
end
|
|
68
47
|
generator.output_context_size
|
|
69
48
|
generator.context
|
|
@@ -75,6 +54,9 @@ module ContextSpook
|
|
|
75
54
|
# assistance.
|
|
76
55
|
class Generator
|
|
77
56
|
include VerbosePuts
|
|
57
|
+
include OutputContext
|
|
58
|
+
|
|
59
|
+
attr_reader :verbose
|
|
78
60
|
|
|
79
61
|
private_class_method :new
|
|
80
62
|
|
|
@@ -85,8 +67,9 @@ module ContextSpook
|
|
|
85
67
|
# output during processing, defaults to lfalse.
|
|
86
68
|
# @param block [ Proc ] a block of code to be evaluated within the object's context
|
|
87
69
|
# If no block is given, the method does nothing.
|
|
88
|
-
def initialize(verbose: false, &block)
|
|
70
|
+
def initialize(verbose: false, format: nil, &block)
|
|
89
71
|
@verbose = !!verbose
|
|
72
|
+
@format = (format || 'JSON').upcase
|
|
90
73
|
block and instance_eval(&block)
|
|
91
74
|
end
|
|
92
75
|
|
|
@@ -98,26 +81,12 @@ module ContextSpook
|
|
|
98
81
|
def context(&block)
|
|
99
82
|
if block
|
|
100
83
|
@context and raise ArgumentError, "only one context allowed"
|
|
101
|
-
@context = Context.new(
|
|
84
|
+
@context = Context.new(generator: self, &block)
|
|
102
85
|
else
|
|
103
86
|
@context
|
|
104
87
|
end
|
|
105
88
|
end
|
|
106
89
|
|
|
107
|
-
# The output_context_size method prints the total size of the generated
|
|
108
|
-
# context JSON representation.
|
|
109
|
-
#
|
|
110
|
-
# This method calculates the size of the context object when serialized to
|
|
111
|
-
# JSON, formats it using binary units (KiB, MiB, etc.), and outputs the
|
|
112
|
-
# result to standard error.
|
|
113
|
-
def output_context_size
|
|
114
|
-
context_size = @context&.size.to_i
|
|
115
|
-
json_content_size = Tins::Unit.format(
|
|
116
|
-
context_size, format: '%.2f %U', unit: ?b, prefix: 1024
|
|
117
|
-
)
|
|
118
|
-
verbose_puts "Built #{json_content_size} of JSON context in total."
|
|
119
|
-
end
|
|
120
|
-
|
|
121
90
|
# The Context class represents and manages project context data, providing
|
|
122
91
|
# structured storage for file contents, command outputs, variables, and
|
|
123
92
|
# metadata that can be serialized to JSON for AI assistance.
|
|
@@ -126,6 +95,7 @@ module ContextSpook
|
|
|
126
95
|
include Tins::Scope
|
|
127
96
|
include Tins::DSLAccessor
|
|
128
97
|
include Term::ANSIColor
|
|
98
|
+
include ContextSpook::TOON
|
|
129
99
|
|
|
130
100
|
# The initialize method sets up the object by evaluating the provided block
|
|
131
101
|
# in the object's context.
|
|
@@ -134,11 +104,15 @@ module ContextSpook
|
|
|
134
104
|
# during processing, defaults to false.
|
|
135
105
|
# @param block [ Proc ] a block of code to be evaluated within the object's context
|
|
136
106
|
# If no block is given, the method does nothing.
|
|
137
|
-
def initialize(
|
|
138
|
-
@
|
|
107
|
+
def initialize(generator:, &block)
|
|
108
|
+
@generator = generator
|
|
139
109
|
block and instance_eval(&block)
|
|
140
110
|
end
|
|
141
111
|
|
|
112
|
+
attr_reader :generator
|
|
113
|
+
|
|
114
|
+
delegate :verbose, to: :generator
|
|
115
|
+
|
|
142
116
|
# The namespace method creates a scoped block with a given name.
|
|
143
117
|
#
|
|
144
118
|
# @param name [ Object ] the name to scope the block with
|
|
@@ -0,0 +1,36 @@
|
|
|
1
|
+
# The ContextSpook::OutputContext module provides methods for outputting
|
|
2
|
+
# context data in various formats.
|
|
3
|
+
#
|
|
4
|
+
# This module is included in the ContextSpook::Generator class to enable output
|
|
5
|
+
# functionality for generated context objects.
|
|
6
|
+
module ContextSpook::OutputContext
|
|
7
|
+
# The output_context_size method prints the total size of the generated
|
|
8
|
+
# context JSON representation.
|
|
9
|
+
#
|
|
10
|
+
# This method calculates the size of the context object when serialized to
|
|
11
|
+
# JSON, formats it using binary units (KiB, MiB, etc.), and outputs the
|
|
12
|
+
# result to standard error.
|
|
13
|
+
def output_context_size
|
|
14
|
+
context_size =
|
|
15
|
+
(@format == 'TOON' ? @context&.toon_size : @context&.size).to_i
|
|
16
|
+
context_size = ContextSpook::Utils.format_size(context_size)
|
|
17
|
+
verbose_puts "Built #{context_size} of #@format context in total."
|
|
18
|
+
end
|
|
19
|
+
|
|
20
|
+
# The output_context method writes the generated context to the specified
|
|
21
|
+
# output stream in either TOON or JSON format.
|
|
22
|
+
#
|
|
23
|
+
# This method serializes the context object into either TOON format or JSON
|
|
24
|
+
# format depending on the configured format, and writes the result to the
|
|
25
|
+
# provided output stream, which defaults to STDOUT.
|
|
26
|
+
#
|
|
27
|
+
# @param output [ IO ] the output stream to write the context data to,
|
|
28
|
+
# defaults to STDOUT
|
|
29
|
+
def output_context(output: STDOUT)
|
|
30
|
+
if @format == 'TOON'
|
|
31
|
+
output.puts(@context.to_toon)
|
|
32
|
+
else
|
|
33
|
+
JSON.dump(@context.as_json, output)
|
|
34
|
+
end
|
|
35
|
+
end
|
|
36
|
+
end
|
|
@@ -0,0 +1,20 @@
|
|
|
1
|
+
require 'ruby_json_toon'
|
|
2
|
+
|
|
3
|
+
# The ContextSpook::TOON module provides TOON (Token-Oriented Object Notation)
|
|
4
|
+
# serialization functionality for context objects.
|
|
5
|
+
module ContextSpook::TOON
|
|
6
|
+
# Converts the context object to TOON format.
|
|
7
|
+
#
|
|
8
|
+
# @return [String] the TOON-encoded representation of the context
|
|
9
|
+
def to_toon
|
|
10
|
+
RubyJsonToon.encode(as_json)
|
|
11
|
+
end
|
|
12
|
+
memoize method: :to_toon
|
|
13
|
+
|
|
14
|
+
# Calculates the size of the TOON representation.
|
|
15
|
+
#
|
|
16
|
+
# @return [Integer] the size in bytes of the TOON representation
|
|
17
|
+
def toon_size
|
|
18
|
+
to_toon.size
|
|
19
|
+
end
|
|
20
|
+
end
|
|
@@ -0,0 +1,19 @@
|
|
|
1
|
+
# The ContextSpook::Utils module provides utility methods for formatting and
|
|
2
|
+
# processing context data.
|
|
3
|
+
module ContextSpook::Utils
|
|
4
|
+
module_function
|
|
5
|
+
|
|
6
|
+
# The format_size method converts a byte size value into a human-readable
|
|
7
|
+
# string with binary units.
|
|
8
|
+
#
|
|
9
|
+
# This method takes a raw byte count and formats it using the Tins::Unit
|
|
10
|
+
# library to display the size with appropriate binary prefixes (KiB, MiB,
|
|
11
|
+
# etc.) and two decimal places.
|
|
12
|
+
#
|
|
13
|
+
# @param context_size [ Integer ] the size in bytes to be formatted
|
|
14
|
+
#
|
|
15
|
+
# @return [ String ] the formatted size string with binary units
|
|
16
|
+
def format_size(context_size)
|
|
17
|
+
Tins::Unit.format(context_size, format: '%.2f %U', unit: ?b, prefix: 1024)
|
|
18
|
+
end
|
|
19
|
+
end
|
|
@@ -0,0 +1,25 @@
|
|
|
1
|
+
module ContextSpook
|
|
2
|
+
# The VerbosePuts module provides a conditional output mechanism for
|
|
3
|
+
# displaying status or debug messages.
|
|
4
|
+
#
|
|
5
|
+
# This module includes a method that outputs messages to standard error only
|
|
6
|
+
# when a verbose flag is enabled. It is designed to be included in classes
|
|
7
|
+
# that need to conditionally emit verbose logging information during
|
|
8
|
+
# processing.
|
|
9
|
+
module VerbosePuts
|
|
10
|
+
# The verbose_puts method outputs the given arguments to standard error
|
|
11
|
+
# only if verbose mode is enabled.
|
|
12
|
+
#
|
|
13
|
+
# This method serves as a conditional output mechanism, allowing debug or
|
|
14
|
+
# status messages to be displayed based on the verbosity setting of the
|
|
15
|
+
# object.
|
|
16
|
+
#
|
|
17
|
+
# @param a [ Array ] the arguments to be printed to standard error
|
|
18
|
+
#
|
|
19
|
+
# @return [ nil ] always returns nil after attempting to output
|
|
20
|
+
def verbose_puts(*a)
|
|
21
|
+
verbose or return
|
|
22
|
+
STDERR.puts(a)
|
|
23
|
+
end
|
|
24
|
+
end
|
|
25
|
+
end
|
data/lib/context_spook.rb
CHANGED
|
@@ -1,56 +1,92 @@
|
|
|
1
1
|
require 'spec_helper'
|
|
2
2
|
|
|
3
3
|
describe ContextSpook::Generator do
|
|
4
|
-
let :
|
|
5
|
-
ContextSpook.generate_context('.contexts/project.rb', verbose:
|
|
4
|
+
let :my_context do
|
|
5
|
+
ContextSpook.generate_context('.contexts/project.rb', verbose: false)
|
|
6
6
|
end
|
|
7
7
|
|
|
8
|
-
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
|
|
8
|
+
describe 'generating w/o verbose' do
|
|
9
|
+
it 'context can be generated from block' do
|
|
10
|
+
expect_any_instance_of(described_class).to\
|
|
11
|
+
receive(:output_context_size).and_call_original
|
|
12
|
+
my_context = ContextSpook.generate_context do
|
|
13
|
+
context do
|
|
14
|
+
variable foo: 'bar'
|
|
15
|
+
metadata version: '1.0'
|
|
16
|
+
end
|
|
15
17
|
end
|
|
18
|
+
expect(my_context).to be_a described_class::Context
|
|
19
|
+
expect(my_context.variables[:foo]).to eq 'bar'
|
|
20
|
+
expect(my_context.metadata[:version]).to eq '1.0'
|
|
16
21
|
end
|
|
17
|
-
expect(context).to be_a described_class::Context
|
|
18
|
-
expect(context.variables[:foo]).to eq 'bar'
|
|
19
|
-
expect(context.metadata[:version]).to eq '1.0'
|
|
20
|
-
end
|
|
21
22
|
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
|
|
23
|
+
it 'context can be generated from filename' do
|
|
24
|
+
expect_any_instance_of(described_class).to\
|
|
25
|
+
receive(:output_context_size).and_call_original
|
|
26
|
+
expect(my_context).to be_a described_class::Context
|
|
27
|
+
expect(my_context.metadata[:ruby]).to eq RUBY_DESCRIPTION
|
|
28
|
+
end
|
|
28
29
|
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
|
|
30
|
+
it 'could handle premature output_context_size calls' do
|
|
31
|
+
expect_any_instance_of(described_class).to\
|
|
32
|
+
receive(:output_context_size).and_call_original
|
|
33
|
+
described_class.send(:new).output_context_size
|
|
34
|
+
end
|
|
35
|
+
|
|
36
|
+
it 'cannot do from block and filename' do
|
|
37
|
+
expect {
|
|
38
|
+
ContextSpook.generate_context('.contexts/project.rb') { }
|
|
39
|
+
}.to raise_error(ArgumentError, /need either a filename or a &block/)
|
|
40
|
+
end
|
|
34
41
|
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
|
|
42
|
+
it 'context be transformed to JSON if loaded' do
|
|
43
|
+
context_as_json = my_context.to_json
|
|
44
|
+
expect(my_context.size).to be > 1024
|
|
45
|
+
expect(JSON(context_as_json)).to be_a Hash
|
|
46
|
+
end
|
|
47
|
+
|
|
48
|
+
it 'can output context in JSON' do
|
|
49
|
+
output = StringIO.new
|
|
50
|
+
expect_any_instance_of(described_class).to receive(:output_context).
|
|
51
|
+
with(output:).and_call_original
|
|
52
|
+
my_context.generator.output_context(output:)
|
|
53
|
+
expect(output.string).to include '"ruby":%s' % RUBY_DESCRIPTION.dump
|
|
54
|
+
end
|
|
55
|
+
|
|
56
|
+
it 'can output context in TOON' do
|
|
57
|
+
my_context = ContextSpook.generate_context(
|
|
58
|
+
'.contexts/project.rb', verbose: false, format: 'TOON'
|
|
59
|
+
)
|
|
60
|
+
output = StringIO.new
|
|
61
|
+
expect_any_instance_of(described_class).to receive(:output_context).
|
|
62
|
+
with(output:).and_call_original
|
|
63
|
+
my_context.generator.output_context(output:)
|
|
64
|
+
expect(output.string).to include 'ruby: %s' % RUBY_DESCRIPTION.dump
|
|
65
|
+
end
|
|
39
66
|
end
|
|
40
67
|
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
|
|
68
|
+
describe 'generating with verbose' do
|
|
69
|
+
let :my_context do
|
|
70
|
+
ContextSpook.generate_context('.contexts/project.rb', verbose: true)
|
|
71
|
+
end
|
|
72
|
+
|
|
73
|
+
it 'can output context size' do
|
|
74
|
+
expect_any_instance_of(described_class).to receive(:output_context_size).
|
|
75
|
+
and_call_original
|
|
76
|
+
expect_any_instance_of(described_class).to receive(:verbose_puts).
|
|
77
|
+
with(/Built.*of JSON context in total/)
|
|
78
|
+
allow_any_instance_of(described_class::Context).to receive(:verbose_puts)
|
|
79
|
+
my_context
|
|
80
|
+
end
|
|
45
81
|
end
|
|
46
82
|
|
|
47
83
|
describe 'Context' do
|
|
48
84
|
it 'can have variables' do
|
|
49
|
-
expect(
|
|
85
|
+
expect(my_context.variables[:branch]).to be_present
|
|
50
86
|
end
|
|
51
87
|
|
|
52
88
|
it 'can have files' do
|
|
53
|
-
file =
|
|
89
|
+
file = my_context.files['lib/context_spook.rb']
|
|
54
90
|
expect(file).to be_present
|
|
55
91
|
expect(file[:content]).to be_present
|
|
56
92
|
expect(file[:content_types]).to be_present
|
|
@@ -61,7 +97,7 @@ describe ContextSpook::Generator do
|
|
|
61
97
|
end
|
|
62
98
|
|
|
63
99
|
it 'can have commands' do
|
|
64
|
-
command =
|
|
100
|
+
command = my_context.commands['tree']
|
|
65
101
|
expect(command).to be_present
|
|
66
102
|
expect(command[:working_directory]).to eq Dir.pwd
|
|
67
103
|
expect(command[:exit_code]).not_to be_nil
|
|
@@ -74,38 +110,38 @@ describe ContextSpook::Generator do
|
|
|
74
110
|
end
|
|
75
111
|
|
|
76
112
|
it 'can have metada' do
|
|
77
|
-
expect(
|
|
113
|
+
expect(my_context.metadata[:ruby]).to eq RUBY_DESCRIPTION
|
|
78
114
|
end
|
|
79
115
|
|
|
80
116
|
it 'can have json metadata' do
|
|
81
|
-
expect(
|
|
117
|
+
expect(my_context.metadata[:hello_world]).to eq("hello" => "world")
|
|
82
118
|
end
|
|
83
119
|
|
|
84
120
|
it 'can have yaml metadata' do
|
|
85
|
-
expect(
|
|
121
|
+
expect(my_context.metadata[:hey_world]).to eq("hey" => "world")
|
|
86
122
|
end
|
|
87
123
|
|
|
88
124
|
it 'handles missing json files gracefully' do
|
|
89
|
-
expect(
|
|
125
|
+
expect(my_context.json('nixda.json')).to be_nil
|
|
90
126
|
end
|
|
91
127
|
|
|
92
128
|
it 'handles invalid json content gracefully' do
|
|
93
129
|
Tempfile.create('invalid.json') do |f|
|
|
94
130
|
f.write('{ invalid json }')
|
|
95
131
|
f.close
|
|
96
|
-
expect(
|
|
132
|
+
expect(my_context.json(f.path)).to be_nil
|
|
97
133
|
end
|
|
98
134
|
end
|
|
99
135
|
|
|
100
136
|
it 'handles missing yaml files gracefully' do
|
|
101
|
-
expect(
|
|
137
|
+
expect(my_context.yaml('nixda.yaml')).to be_nil
|
|
102
138
|
end
|
|
103
139
|
|
|
104
140
|
it 'handles invalid yaml content gracefully' do
|
|
105
141
|
Tempfile.create('invalid.yaml') do |f|
|
|
106
142
|
f.write('invalid: [yaml')
|
|
107
143
|
f.close
|
|
108
|
-
expect(
|
|
144
|
+
expect(my_context.yaml(f.path)).to be_nil
|
|
109
145
|
end
|
|
110
146
|
end
|
|
111
147
|
end
|
|
@@ -0,0 +1,56 @@
|
|
|
1
|
+
require 'spec_helper'
|
|
2
|
+
|
|
3
|
+
describe ContextSpook::TOON do
|
|
4
|
+
let(:context) do
|
|
5
|
+
ContextSpook.generate_context do
|
|
6
|
+
context do
|
|
7
|
+
variable foo: 'bar'
|
|
8
|
+
metadata version: '1.0'
|
|
9
|
+
file 'lib/context_spook.rb'
|
|
10
|
+
end
|
|
11
|
+
end
|
|
12
|
+
end
|
|
13
|
+
|
|
14
|
+
describe '#to_toon' do
|
|
15
|
+
it 'converts context to TOON format' do
|
|
16
|
+
toon_output = context.to_toon
|
|
17
|
+
expect(toon_output).to be_a(String)
|
|
18
|
+
expect(toon_output).to_not be_empty
|
|
19
|
+
end
|
|
20
|
+
|
|
21
|
+
it 'produces valid TOON output' do
|
|
22
|
+
toon_output = context.to_toon
|
|
23
|
+
# TOON should be a valid string representation
|
|
24
|
+
expect { RubyJsonToon.decode(toon_output) }.not_to raise_error
|
|
25
|
+
end
|
|
26
|
+
end
|
|
27
|
+
|
|
28
|
+
describe '#toon_size' do
|
|
29
|
+
it 'returns the size of TOON representation in bytes' do
|
|
30
|
+
size = context.toon_size
|
|
31
|
+
expect(size).to be_a(Integer)
|
|
32
|
+
expect(size).to be > 0
|
|
33
|
+
end
|
|
34
|
+
|
|
35
|
+
it 'matches the size of the TOON output' do
|
|
36
|
+
size = context.toon_size
|
|
37
|
+
toon_output = context.to_toon
|
|
38
|
+
expect(size).to eq(toon_output.size)
|
|
39
|
+
end
|
|
40
|
+
end
|
|
41
|
+
|
|
42
|
+
describe 'integration with ContextSpook::Generator::Context' do
|
|
43
|
+
it 'is included in Context class' do
|
|
44
|
+
expect(context).to respond_to(:to_toon)
|
|
45
|
+
expect(context).to respond_to(:toon_size)
|
|
46
|
+
end
|
|
47
|
+
|
|
48
|
+
it 'works with context data' do
|
|
49
|
+
toon_output = context.to_toon
|
|
50
|
+
expect(toon_output).to include('variables:')
|
|
51
|
+
expect(toon_output).to include('metadata:')
|
|
52
|
+
expect(toon_output).to include('files:')
|
|
53
|
+
expect(toon_output).to include('commands:')
|
|
54
|
+
end
|
|
55
|
+
end
|
|
56
|
+
end
|
metadata
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
|
2
2
|
name: context_spook
|
|
3
3
|
version: !ruby/object:Gem::Version
|
|
4
|
-
version: 1.
|
|
4
|
+
version: 1.3.0
|
|
5
5
|
platform: ruby
|
|
6
6
|
authors:
|
|
7
7
|
- Florian Frank
|
|
@@ -15,14 +15,14 @@ dependencies:
|
|
|
15
15
|
requirements:
|
|
16
16
|
- - ">="
|
|
17
17
|
- !ruby/object:Gem::Version
|
|
18
|
-
version: 2.
|
|
18
|
+
version: 2.17.0
|
|
19
19
|
type: :development
|
|
20
20
|
prerelease: false
|
|
21
21
|
version_requirements: !ruby/object:Gem::Requirement
|
|
22
22
|
requirements:
|
|
23
23
|
- - ">="
|
|
24
24
|
- !ruby/object:Gem::Version
|
|
25
|
-
version: 2.
|
|
25
|
+
version: 2.17.0
|
|
26
26
|
- !ruby/object:Gem::Dependency
|
|
27
27
|
name: all_images
|
|
28
28
|
requirement: !ruby/object:Gem::Requirement
|
|
@@ -177,6 +177,20 @@ dependencies:
|
|
|
177
177
|
- - "~>"
|
|
178
178
|
- !ruby/object:Gem::Version
|
|
179
179
|
version: '0.4'
|
|
180
|
+
- !ruby/object:Gem::Dependency
|
|
181
|
+
name: ruby-json-toon
|
|
182
|
+
requirement: !ruby/object:Gem::Requirement
|
|
183
|
+
requirements:
|
|
184
|
+
- - "~>"
|
|
185
|
+
- !ruby/object:Gem::Version
|
|
186
|
+
version: '1.0'
|
|
187
|
+
type: :runtime
|
|
188
|
+
prerelease: false
|
|
189
|
+
version_requirements: !ruby/object:Gem::Requirement
|
|
190
|
+
requirements:
|
|
191
|
+
- - "~>"
|
|
192
|
+
- !ruby/object:Gem::Version
|
|
193
|
+
version: '1.0'
|
|
180
194
|
description: |
|
|
181
195
|
context_spook is a library that collects and organizes project
|
|
182
196
|
information to help AI assistants understand codebases better.
|
|
@@ -188,6 +202,10 @@ extra_rdoc_files:
|
|
|
188
202
|
- README.md
|
|
189
203
|
- lib/context_spook.rb
|
|
190
204
|
- lib/context_spook/generator.rb
|
|
205
|
+
- lib/context_spook/output_context.rb
|
|
206
|
+
- lib/context_spook/toon.rb
|
|
207
|
+
- lib/context_spook/utils.rb
|
|
208
|
+
- lib/context_spook/verbose_puts.rb
|
|
191
209
|
- lib/context_spook/version.rb
|
|
192
210
|
files:
|
|
193
211
|
- ".contexts/project.rb"
|
|
@@ -201,8 +219,13 @@ files:
|
|
|
201
219
|
- hey_world.yaml
|
|
202
220
|
- lib/context_spook.rb
|
|
203
221
|
- lib/context_spook/generator.rb
|
|
222
|
+
- lib/context_spook/output_context.rb
|
|
223
|
+
- lib/context_spook/toon.rb
|
|
224
|
+
- lib/context_spook/utils.rb
|
|
225
|
+
- lib/context_spook/verbose_puts.rb
|
|
204
226
|
- lib/context_spook/version.rb
|
|
205
227
|
- spec/context_spook/generator_spec.rb
|
|
228
|
+
- spec/context_spook/toon_spec.rb
|
|
206
229
|
- spec/spec_helper.rb
|
|
207
230
|
homepage: https://github.com/flori/context_spook
|
|
208
231
|
licenses:
|
|
@@ -231,4 +254,5 @@ specification_version: 4
|
|
|
231
254
|
summary: context_spook collects project context for AI
|
|
232
255
|
test_files:
|
|
233
256
|
- spec/context_spook/generator_spec.rb
|
|
257
|
+
- spec/context_spook/toon_spec.rb
|
|
234
258
|
- spec/spec_helper.rb
|