context_spook 0.0.1 → 0.2.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/README.md +49 -10
- data/Rakefile +1 -0
- data/bin/context_spook +0 -4
- data/context_spook.gemspec +4 -3
- data/contexts/project.rb +6 -2
- data/hello_world.json +3 -0
- data/lib/context_spook/generator.rb +62 -3
- data/lib/context_spook/version.rb +1 -1
- data/spec/context_spook/generator_spec.rb +31 -4
- metadata +16 -1
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA256:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: 4088e8a4f8de00062dcea1b56b696dd1190731c0c30944a95c60a14cad995fa9
|
4
|
+
data.tar.gz: 996fb30d8a2542a387451416ece827dd1b8062344317ef798db803c216d39e17
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: df6ce1080b5b98a1e279f945cb0e5934592ea586c15abc24234b1c44aaa0d5aac55308227c2966a1e2e9912f620f4d13a5bda0940726028f589aa0ee522dc3fd
|
7
|
+
data.tar.gz: 2b787ae025a227d47f7d6ab53d850bc0c2084a6872e16bb2b60d122965d3dcdb17531fc4118371de82da0edcdd29b7a4ebe143b55019d3116bb424117edb85f4
|
data/README.md
CHANGED
@@ -32,8 +32,46 @@ $ gem install context_spook
|
|
32
32
|
|
33
33
|
## Usage
|
34
34
|
|
35
|
-
|
36
|
-
|
35
|
+
### Programmatic Usage
|
36
|
+
|
37
|
+
#### Directly in Ruby
|
38
|
+
|
39
|
+
Now you can generate context from a block directly in Ruby using the DSL:
|
40
|
+
|
41
|
+
```ruby
|
42
|
+
context = ContextSpook::generate_context do
|
43
|
+
context do
|
44
|
+
variable branch: `git rev-parse --abbrev-ref HEAD`.chomp
|
45
|
+
|
46
|
+
namespace "structure" do
|
47
|
+
command "tree", tags: %w[ project_structure ]
|
48
|
+
end
|
49
|
+
|
50
|
+
namespace "lib" do
|
51
|
+
Dir['lib/**/*.rb'].each do |filename|
|
52
|
+
file filename, tags: 'lib'
|
53
|
+
end
|
54
|
+
end
|
55
|
+
|
56
|
+
# ... rest of your context definition, see below for full example
|
57
|
+
end
|
58
|
+
end
|
59
|
+
```
|
60
|
+
|
61
|
+
This approach can be used to dynamically generate a context when it is not
|
62
|
+
configurable via a user context definition file, or as a fallback when users
|
63
|
+
have not yet created such files.
|
64
|
+
|
65
|
+
Afterwards you can store the context as JSON in Ruby or send it to another
|
66
|
+
application.
|
67
|
+
|
68
|
+
```ruby
|
69
|
+
File.write 'context.json', context.to_json
|
70
|
+
```
|
71
|
+
|
72
|
+
#### From a context definition file
|
73
|
+
|
74
|
+
Alternatively store the block's content above to a file `contexts/project.rb`:
|
37
75
|
|
38
76
|
```ruby
|
39
77
|
# contexts/project.rb
|
@@ -41,7 +79,7 @@ context do
|
|
41
79
|
variable branch: `git rev-parse --abbrev-ref HEAD`.chomp
|
42
80
|
|
43
81
|
namespace "structure" do
|
44
|
-
command "tree
|
82
|
+
command "tree", tags: %w[ project_structure ]
|
45
83
|
end
|
46
84
|
|
47
85
|
namespace "lib" do
|
@@ -68,13 +106,12 @@ context do
|
|
68
106
|
|
69
107
|
meta ruby: RUBY_DESCRIPTION
|
70
108
|
|
71
|
-
meta code_coverage:
|
109
|
+
meta code_coverage: json('coverage/coverage_context.json')
|
72
110
|
end
|
73
111
|
```
|
74
112
|
|
75
|
-
|
76
|
-
|
77
|
-
Now you can generate the context from the file, and store it as JSON in Ruby.
|
113
|
+
Now you can generate the context from the file, and store it as JSON in Ruby or
|
114
|
+
send it to another application.
|
78
115
|
|
79
116
|
```ruby
|
80
117
|
context = ContextSpook::generate_context('contexts/project.rb')
|
@@ -129,11 +166,13 @@ assistants understand:
|
|
129
166
|
"content": "...",
|
130
167
|
"size": 1234,
|
131
168
|
"lines": 56,
|
132
|
-
"tags": [
|
169
|
+
"tags": [
|
170
|
+
"lib"
|
171
|
+
]
|
133
172
|
}
|
134
173
|
},
|
135
174
|
"commands": {
|
136
|
-
"tree
|
175
|
+
"tree": {
|
137
176
|
"namespace": "structure",
|
138
177
|
"output": "lib\n├── context_spook\n│ └── generator.rb\n└── context_spook.rb\n\n2 directories, 3 files",
|
139
178
|
"exit_code": 0,
|
@@ -142,7 +181,7 @@ assistants understand:
|
|
142
181
|
},
|
143
182
|
"metadata": {
|
144
183
|
"ruby": "ruby 3.1.0 ...",
|
145
|
-
"code_coverage": {
|
184
|
+
"code_coverage": {}
|
146
185
|
},
|
147
186
|
"variables": {
|
148
187
|
"branch": "main"
|
data/Rakefile
CHANGED
@@ -29,6 +29,7 @@ GemHadar do
|
|
29
29
|
dependency 'tins', '~>1.39'
|
30
30
|
dependency 'json', '~>2.0'
|
31
31
|
dependency 'term-ansicolor', '~> 1.11'
|
32
|
+
dependency 'mize', '~> 0.6'
|
32
33
|
development_dependency 'all_images', '~> 0.6'
|
33
34
|
development_dependency 'rspec', '~> 3.2'
|
34
35
|
development_dependency 'debug'
|
data/bin/context_spook
CHANGED
@@ -4,8 +4,4 @@ require 'context_spook'
|
|
4
4
|
|
5
5
|
filename = ARGV.shift or fail 'require context definition file as first argument'
|
6
6
|
context_json = ContextSpook.generate_context(filename).to_json
|
7
|
-
context_json_size = Tins::Unit.format(
|
8
|
-
context_json.size, format: '%.2f %U', unit: ?b, prefix: 1024
|
9
|
-
)
|
10
|
-
STDERR.puts "Now outputting #{context_json_size} of JSON context in total."
|
11
7
|
puts context_json
|
data/context_spook.gemspec
CHANGED
@@ -1,9 +1,9 @@
|
|
1
1
|
# -*- encoding: utf-8 -*-
|
2
|
-
# stub: context_spook 0.0
|
2
|
+
# stub: context_spook 0.2.0 ruby lib
|
3
3
|
|
4
4
|
Gem::Specification.new do |s|
|
5
5
|
s.name = "context_spook".freeze
|
6
|
-
s.version = "0.0
|
6
|
+
s.version = "0.2.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]
|
@@ -13,7 +13,7 @@ Gem::Specification.new do |s|
|
|
13
13
|
s.email = "flori@ping.de".freeze
|
14
14
|
s.executables = ["context_spook".freeze]
|
15
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 = ["Gemfile".freeze, "LICENSE".freeze, "README.md".freeze, "Rakefile".freeze, "bin/context_spook".freeze, "context_spook.gemspec".freeze, "contexts/project.rb".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]
|
16
|
+
s.files = ["Gemfile".freeze, "LICENSE".freeze, "README.md".freeze, "Rakefile".freeze, "bin/context_spook".freeze, "context_spook.gemspec".freeze, "contexts/project.rb".freeze, "hello_world.json".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]
|
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]
|
@@ -32,4 +32,5 @@ Gem::Specification.new do |s|
|
|
32
32
|
s.add_runtime_dependency(%q<tins>.freeze, ["~> 1.39".freeze])
|
33
33
|
s.add_runtime_dependency(%q<json>.freeze, ["~> 2.0".freeze])
|
34
34
|
s.add_runtime_dependency(%q<term-ansicolor>.freeze, ["~> 1.11".freeze])
|
35
|
+
s.add_runtime_dependency(%q<mize>.freeze, ["~> 0.6".freeze])
|
35
36
|
end
|
data/contexts/project.rb
CHANGED
@@ -2,7 +2,7 @@ context do
|
|
2
2
|
variable branch: `git rev-parse --abbrev-ref HEAD`.chomp
|
3
3
|
|
4
4
|
namespace "structure" do
|
5
|
-
command "tree
|
5
|
+
command "tree", tags: %w[ project_structure ]
|
6
6
|
end
|
7
7
|
|
8
8
|
namespace "lib" do
|
@@ -35,5 +35,9 @@ context do
|
|
35
35
|
|
36
36
|
meta ruby: RUBY_DESCRIPTION
|
37
37
|
|
38
|
-
meta
|
38
|
+
meta hello_world: json('hello_world.json')
|
39
|
+
|
40
|
+
meta nixda_json: json('nixda_json.json')
|
41
|
+
|
42
|
+
meta code_coverage: json('coverage/coverage_context.json')
|
39
43
|
end
|
data/hello_world.json
ADDED
@@ -1,7 +1,7 @@
|
|
1
1
|
require 'tins/xt'
|
2
2
|
require 'term/ansicolor'
|
3
3
|
require 'json'
|
4
|
-
|
4
|
+
require 'mize'
|
5
5
|
|
6
6
|
# The ContextSpook module serves as a namespace container for collecting and
|
7
7
|
# organizing project information for AI assistance.
|
@@ -19,8 +19,16 @@ module ContextSpook
|
|
19
19
|
#
|
20
20
|
# @return [ ContextSpook::Generator::Context ] the context object generated
|
21
21
|
# from the file contents
|
22
|
-
def self.generate_context(filename)
|
23
|
-
|
22
|
+
def self.generate_context(filename = nil, &block)
|
23
|
+
filename.present? ^ block or
|
24
|
+
raise ArgumentError, 'need either a filename or a &block argument'
|
25
|
+
generator = if filename
|
26
|
+
Generator.send(:new).send(:parse, File.read(filename))
|
27
|
+
else
|
28
|
+
Generator.send(:new, &block)
|
29
|
+
end
|
30
|
+
generator.output_context_size
|
31
|
+
generator.context
|
24
32
|
end
|
25
33
|
|
26
34
|
# The Generator class provides a DSL parser that interprets context
|
@@ -52,6 +60,20 @@ module ContextSpook
|
|
52
60
|
end
|
53
61
|
end
|
54
62
|
|
63
|
+
# The output_context_size method prints the total size of the generated
|
64
|
+
# context JSON representation.
|
65
|
+
#
|
66
|
+
# This method calculates the size of the context object when serialized to
|
67
|
+
# JSON, formats it using binary units (KiB, MiB, etc.), and outputs the
|
68
|
+
# result to standard error.
|
69
|
+
def output_context_size
|
70
|
+
context_size = @context&.size.to_i
|
71
|
+
json_content_size = Tins::Unit.format(
|
72
|
+
context_size, format: '%.2f %U', unit: ?b, prefix: 1024
|
73
|
+
)
|
74
|
+
STDERR.puts "Built #{json_content_size} of JSON context in total."
|
75
|
+
end
|
76
|
+
|
55
77
|
# The Context class represents and manages project context data, providing
|
56
78
|
# structured storage for file contents, command outputs, variables, and
|
57
79
|
# metadata that can be serialized to JSON for AI assistance.
|
@@ -117,6 +139,29 @@ module ContextSpook
|
|
117
139
|
nil
|
118
140
|
end
|
119
141
|
|
142
|
+
# The json method reads and parses a JSON file, returning the parsed data
|
143
|
+
# structure.
|
144
|
+
#
|
145
|
+
# This method attempts to load a JSON file from the specified path and
|
146
|
+
# returns the resulting Ruby data structure. It provides verbose output
|
147
|
+
# about the file size when successfully reading the file. In case of file
|
148
|
+
# not found errors, it outputs a colored warning message to standard
|
149
|
+
# error and returns nil.
|
150
|
+
#
|
151
|
+
# @param filename [ String ] the path to the JSON file to be read and parsed
|
152
|
+
#
|
153
|
+
# @return [ Object, nil ] the parsed JSON data structure or nil if the file cannot be read
|
154
|
+
def json(filename)
|
155
|
+
file_size = Tins::Unit.format(
|
156
|
+
File.size(filename), format: '%.2f %U', unit: ?b, prefix: 1024
|
157
|
+
)
|
158
|
+
STDERR.puts "Read #{filename.inspect} as JSON (%s) for context." % file_size
|
159
|
+
JSON.load_file(filename)
|
160
|
+
rescue Errno::ENOENT => e
|
161
|
+
STDERR.puts color(208) { "Reading #{filename.inspect} as JSON caused #{e.class}: #{e}" }
|
162
|
+
nil
|
163
|
+
end
|
164
|
+
|
120
165
|
# The files method sets up a DSL accessor for providing files.
|
121
166
|
#
|
122
167
|
# @param default [ Hash ] the default files hash
|
@@ -191,6 +236,7 @@ module ContextSpook
|
|
191
236
|
# The to_json method converts the object to a JSON representation by
|
192
237
|
# first generating its hash form and then serializing that hash into JSON
|
193
238
|
# format.
|
239
|
+
memoize method:
|
194
240
|
def to_json(*)
|
195
241
|
as_json.to_json(*)
|
196
242
|
end
|
@@ -207,6 +253,19 @@ module ContextSpook
|
|
207
253
|
variables:
|
208
254
|
}
|
209
255
|
end
|
256
|
+
|
257
|
+
# The size method calculates and returns the byte size of the JSON
|
258
|
+
# representation of the context.
|
259
|
+
#
|
260
|
+
# This method determines the size in bytes of the JSON-serialized version
|
261
|
+
# of the context object, which is useful for understanding the total data
|
262
|
+
# payload being sent to an AI assistant.
|
263
|
+
#
|
264
|
+
# @return [ Integer ] the size in bytes of the JSON representation of the
|
265
|
+
# context
|
266
|
+
def size
|
267
|
+
to_json.size
|
268
|
+
end
|
210
269
|
end
|
211
270
|
|
212
271
|
private
|
@@ -5,19 +5,46 @@ describe ContextSpook::Generator do
|
|
5
5
|
ContextSpook.generate_context('contexts/project.rb')
|
6
6
|
end
|
7
7
|
|
8
|
-
it 'context can be generated' do
|
8
|
+
it 'context can be generated from block' do
|
9
|
+
expect_any_instance_of(described_class).to\
|
10
|
+
receive(:output_context_size).and_call_original
|
11
|
+
context = ContextSpook.generate_context do
|
12
|
+
context do
|
13
|
+
variable foo: 'bar'
|
14
|
+
metadata version: '1.0'
|
15
|
+
end
|
16
|
+
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
|
+
it 'context can be generated from filename' do
|
23
|
+
expect_any_instance_of(described_class).to\
|
24
|
+
receive(:output_context_size).and_call_original
|
9
25
|
expect(context).to be_a described_class::Context
|
10
26
|
expect(context.metadata[:ruby]).to eq RUBY_DESCRIPTION
|
11
27
|
end
|
12
28
|
|
29
|
+
it 'could handle premature output_context_size calls' do
|
30
|
+
expect_any_instance_of(described_class).to\
|
31
|
+
receive(:output_context_size).and_call_original
|
32
|
+
described_class.send(:new).output_context_size
|
33
|
+
end
|
34
|
+
|
35
|
+
it 'cannot do from block and filename' do
|
36
|
+
expect {
|
37
|
+
ContextSpook.generate_context('contexts/project.rb') { }
|
38
|
+
}.to raise_error(ArgumentError, /need either a filename or a &block/)
|
39
|
+
end
|
40
|
+
|
13
41
|
it 'context be transformed to JSON if loaded' do
|
14
42
|
context_as_json = context.to_json
|
15
|
-
expect(
|
43
|
+
expect(context.size).to be > 1024
|
16
44
|
expect(JSON(context_as_json)).to be_a Hash
|
17
45
|
end
|
18
46
|
|
19
47
|
describe 'Context' do
|
20
|
-
|
21
48
|
it 'can have variables' do
|
22
49
|
expect(context.variables[:branch]).to be_present
|
23
50
|
end
|
@@ -33,7 +60,7 @@ describe ContextSpook::Generator do
|
|
33
60
|
end
|
34
61
|
|
35
62
|
it 'can have commands' do
|
36
|
-
command = context.commands['tree
|
63
|
+
command = context.commands['tree']
|
37
64
|
expect(command).to be_present
|
38
65
|
expect(command[:working_directory]).to eq Dir.pwd
|
39
66
|
expect(command[:exit_code]).to be_present
|
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: 0.0
|
4
|
+
version: 0.2.0
|
5
5
|
platform: ruby
|
6
6
|
authors:
|
7
7
|
- Florian Frank
|
@@ -121,6 +121,20 @@ dependencies:
|
|
121
121
|
- - "~>"
|
122
122
|
- !ruby/object:Gem::Version
|
123
123
|
version: '1.11'
|
124
|
+
- !ruby/object:Gem::Dependency
|
125
|
+
name: mize
|
126
|
+
requirement: !ruby/object:Gem::Requirement
|
127
|
+
requirements:
|
128
|
+
- - "~>"
|
129
|
+
- !ruby/object:Gem::Version
|
130
|
+
version: '0.6'
|
131
|
+
type: :runtime
|
132
|
+
prerelease: false
|
133
|
+
version_requirements: !ruby/object:Gem::Requirement
|
134
|
+
requirements:
|
135
|
+
- - "~>"
|
136
|
+
- !ruby/object:Gem::Version
|
137
|
+
version: '0.6'
|
124
138
|
description: |
|
125
139
|
context_spook is a library that collects and organizes project
|
126
140
|
information to help AI assistants understand codebases better.
|
@@ -141,6 +155,7 @@ files:
|
|
141
155
|
- bin/context_spook
|
142
156
|
- context_spook.gemspec
|
143
157
|
- contexts/project.rb
|
158
|
+
- hello_world.json
|
144
159
|
- lib/context_spook.rb
|
145
160
|
- lib/context_spook/generator.rb
|
146
161
|
- lib/context_spook/version.rb
|