context_spook 0.3.0 → 0.5.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/{contexts → .contexts}/project.rb +6 -0
- data/README.md +28 -2
- data/Rakefile +6 -1
- data/bin/context_spook +53 -3
- data/context_spook.gemspec +5 -5
- data/lib/context_spook/generator.rb +57 -23
- data/lib/context_spook/version.rb +1 -1
- data/spec/context_spook/generator_spec.rb +3 -3
- metadata +5 -5
checksums.yaml
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
---
|
|
2
2
|
SHA256:
|
|
3
|
-
metadata.gz:
|
|
4
|
-
data.tar.gz:
|
|
3
|
+
metadata.gz: bf46500652e697db299ccdfe21d5dd4c02953b699ca528b21810f87348eddceb
|
|
4
|
+
data.tar.gz: ad41e6c9f6141ba5303c845aaf26c2d141125201d82575834a62efc05c2ae7b8
|
|
5
5
|
SHA512:
|
|
6
|
-
metadata.gz:
|
|
7
|
-
data.tar.gz:
|
|
6
|
+
metadata.gz: edab814b82519dc36f9bb01c4e59dfb372aad6c2e1fa0d8ef7f487a288281ad6bf9bf1474d09a7ff7b818c1a6140ef08c0ba464b986e9bf56a34bd2720f9e778
|
|
7
|
+
data.tar.gz: 052e05ca7fc2825a75b43e1b9a8585344f9d4e8a6a805e3a5d826680d81bfed723d4359db7083d6451ce4afa6e35e82688a979dae0fcd0dcde401784d373b2de
|
|
@@ -5,6 +5,12 @@ context do
|
|
|
5
5
|
command "tree", tags: %w[ project_structure ]
|
|
6
6
|
end
|
|
7
7
|
|
|
8
|
+
namespace "bin" do
|
|
9
|
+
Dir['bin/**/*'].each do |filename|
|
|
10
|
+
file filename, tags: 'bin'
|
|
11
|
+
end
|
|
12
|
+
end
|
|
13
|
+
|
|
8
14
|
namespace "lib" do
|
|
9
15
|
Dir['lib/**/*.rb'].each do |filename|
|
|
10
16
|
file filename, tags: 'lib'
|
data/README.md
CHANGED
|
@@ -12,6 +12,10 @@ information. The `.contexts/project.rb` example below demonstrates how to
|
|
|
12
12
|
describe a Ruby project, but the same principles apply across many different
|
|
13
13
|
domains.
|
|
14
14
|
|
|
15
|
+
## Documentation
|
|
16
|
+
|
|
17
|
+
Complete API documentation is available at: [GitHub.io](https://flori.github.io/context_spook/)
|
|
18
|
+
|
|
15
19
|
## Installation
|
|
16
20
|
|
|
17
21
|
Add this line to your application's Gemfile:
|
|
@@ -128,13 +132,35 @@ Generate context and save to file:
|
|
|
128
132
|
|
|
129
133
|
Or pipe directly to another tool:
|
|
130
134
|
|
|
131
|
-
```
|
|
135
|
+
```bash
|
|
132
136
|
./bin/context_spook .contexts/project.rb | ollama_chat_send
|
|
133
137
|
```
|
|
134
138
|
|
|
135
|
-
|
|
139
|
+
|
|
140
|
+
The CLI tool also supports verbose output:
|
|
141
|
+
|
|
142
|
+
```bash
|
|
143
|
+
# Generate context with verbose output
|
|
144
|
+
./bin/context_spook .contexts/project.rb -v
|
|
145
|
+
```
|
|
146
|
+
|
|
147
|
+
Now you can see two orange warning messages, that demonstrates how errors like
|
|
136
148
|
missing files or commands with failing exit codes are handled.
|
|
137
149
|
|
|
150
|
+
The CLI tool also supports file redirection:
|
|
151
|
+
|
|
152
|
+
```bash
|
|
153
|
+
# Generate context and save to file
|
|
154
|
+
./bin/context_spook .contexts/project.rb -o context.json
|
|
155
|
+
```
|
|
156
|
+
|
|
157
|
+
This is how you can show the usage message:
|
|
158
|
+
|
|
159
|
+
```
|
|
160
|
+
# Show help
|
|
161
|
+
./bin/context_spook -h
|
|
162
|
+
```
|
|
163
|
+
|
|
138
164
|
## What Gets Collected
|
|
139
165
|
|
|
140
166
|
The DSL collects various types of project information:
|
data/Rakefile
CHANGED
|
@@ -9,7 +9,6 @@ GemHadar do
|
|
|
9
9
|
email 'flori@ping.de'
|
|
10
10
|
homepage "https://github.com/flori/context_spook"
|
|
11
11
|
summary "#{name} collects project context for AI"
|
|
12
|
-
executables 'context_spook'
|
|
13
12
|
|
|
14
13
|
description <<~EOT
|
|
15
14
|
#{name} is a library that collects and organizes project
|
|
@@ -24,6 +23,12 @@ GemHadar do
|
|
|
24
23
|
'.rspec', '.github'
|
|
25
24
|
readme 'README.md'
|
|
26
25
|
|
|
26
|
+
executables 'context_spook'
|
|
27
|
+
|
|
28
|
+
github_workflows(
|
|
29
|
+
'static.yml' => {}
|
|
30
|
+
)
|
|
31
|
+
|
|
27
32
|
required_ruby_version '~> 3.1'
|
|
28
33
|
|
|
29
34
|
dependency 'tins', '~>1.39'
|
data/bin/context_spook
CHANGED
|
@@ -1,7 +1,57 @@
|
|
|
1
1
|
#!/usr/bin/env ruby
|
|
2
2
|
|
|
3
3
|
require 'context_spook'
|
|
4
|
+
require 'tins/go'
|
|
5
|
+
include Tins::GO
|
|
6
|
+
require 'json'
|
|
4
7
|
|
|
5
|
-
|
|
6
|
-
|
|
7
|
-
|
|
8
|
+
# The usage method displays the command-line interface help text and example
|
|
9
|
+
# usage patterns for the ContextSpook tool.
|
|
10
|
+
#
|
|
11
|
+
# This method outputs a formatted help message that includes the tool's usage
|
|
12
|
+
# syntax, available options, and practical examples.
|
|
13
|
+
#
|
|
14
|
+
# @see ContextSpook::generate_context
|
|
15
|
+
# @see ContextSpook::Generator
|
|
16
|
+
# @see ContextSpook::Generator::Context
|
|
17
|
+
def usage
|
|
18
|
+
puts <<~EOT
|
|
19
|
+
|
|
20
|
+
Usage: #{File.basename($0)} [options] <context_definition_file>
|
|
21
|
+
|
|
22
|
+
Options:
|
|
23
|
+
-o FILE Write output to FILE instead of stdout
|
|
24
|
+
-v Verbose output
|
|
25
|
+
-h Show this help message
|
|
26
|
+
|
|
27
|
+
Examples:
|
|
28
|
+
# Generate context and output to stdout
|
|
29
|
+
#{File.basename($0)} .contexts/project.rb
|
|
30
|
+
|
|
31
|
+
# Generate context and save to file
|
|
32
|
+
#{File.basename($0)} .contexts/project.rb -o context.json
|
|
33
|
+
|
|
34
|
+
# Generate context with verbose output
|
|
35
|
+
#{File.basename($0)} .contexts/project.rb -v
|
|
36
|
+
|
|
37
|
+
# Generate context and pipe to another tool
|
|
38
|
+
#{File.basename($0)} .contexts/project.rb | ollama_chat_send
|
|
39
|
+
|
|
40
|
+
EOT
|
|
41
|
+
exit 0
|
|
42
|
+
end
|
|
43
|
+
|
|
44
|
+
opts = go 'o:pvh'
|
|
45
|
+
opts[?h] and usage
|
|
46
|
+
filename = ARGV.shift or fail 'require context definition file as an argument'
|
|
47
|
+
output = nil
|
|
48
|
+
context = ContextSpook.generate_context(filename, verbose: opts[?v])
|
|
49
|
+
if output_filename = opts[?o]
|
|
50
|
+
if File.exist?(output_filename)
|
|
51
|
+
fail "Filename #{output_filename.inspect} already exists!"
|
|
52
|
+
end
|
|
53
|
+
output = File.new output_filename, ?w
|
|
54
|
+
else
|
|
55
|
+
output = STDOUT
|
|
56
|
+
end
|
|
57
|
+
JSON.dump(context.as_json, output)
|
data/context_spook.gemspec
CHANGED
|
@@ -1,9 +1,9 @@
|
|
|
1
1
|
# -*- encoding: utf-8 -*-
|
|
2
|
-
# stub: context_spook 0.
|
|
2
|
+
# stub: context_spook 0.5.0 ruby lib
|
|
3
3
|
|
|
4
4
|
Gem::Specification.new do |s|
|
|
5
5
|
s.name = "context_spook".freeze
|
|
6
|
-
s.version = "0.
|
|
6
|
+
s.version = "0.5.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,18 +13,18 @@ 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, "
|
|
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, "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]
|
|
20
20
|
s.required_ruby_version = Gem::Requirement.new("~> 3.1".freeze)
|
|
21
|
-
s.rubygems_version = "3.
|
|
21
|
+
s.rubygems_version = "3.7.2".freeze
|
|
22
22
|
s.summary = "context_spook collects project context for AI".freeze
|
|
23
23
|
s.test_files = ["spec/context_spook/generator_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.8".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])
|
|
@@ -9,24 +9,35 @@ require 'mime-types'
|
|
|
9
9
|
module ContextSpook
|
|
10
10
|
include DSLKit::Interpreter
|
|
11
11
|
|
|
12
|
-
# The generate_context method processes a context definition file
|
|
13
|
-
# the resulting context object.
|
|
12
|
+
# The generate_context method processes a context definition file or block
|
|
13
|
+
# and returns the resulting context object.
|
|
14
14
|
#
|
|
15
|
-
# This method
|
|
16
|
-
#
|
|
17
|
-
#
|
|
15
|
+
# This method serves as the primary entry point for generating project
|
|
16
|
+
# context data. It accepts either a filename pointing to a context definition
|
|
17
|
+
# file or a block containing the context definition, but not both.
|
|
18
|
+
# When a filename is provided, it reads and parses the file content. When a
|
|
19
|
+
# block is provided, it evaluates the block within the generator's context.
|
|
20
|
+
# The method ensures that only one context definition mechanism is used.
|
|
18
21
|
#
|
|
19
|
-
# @param filename [ String ] the path to the context definition file to
|
|
22
|
+
# @param filename [ String, nil ] the path to the context definition file to
|
|
23
|
+
# be processed
|
|
24
|
+
# @param verbose [ TrueClass, FalseClass ] flag to enable verbose output
|
|
25
|
+
# during processing, defaults to false.
|
|
26
|
+
# @param block [ Proc ] a block containing the context definition to be
|
|
27
|
+
# evaluated
|
|
20
28
|
#
|
|
21
29
|
# @return [ ContextSpook::Generator::Context ] the context object generated
|
|
22
|
-
#
|
|
23
|
-
|
|
30
|
+
# from the file contents or block
|
|
31
|
+
#
|
|
32
|
+
# @raise [ ArgumentError ] if neither a filename nor a block is provided
|
|
33
|
+
# @raise [ ArgumentError ] if both a filename and a block are provided
|
|
34
|
+
def self.generate_context(filename = nil, verbose: false, &block)
|
|
24
35
|
filename.present? ^ block or
|
|
25
36
|
raise ArgumentError, 'need either a filename or a &block argument'
|
|
26
37
|
generator = if filename
|
|
27
|
-
Generator.send(:new).send(:parse, File.read(filename))
|
|
38
|
+
Generator.send(:new, verbose:).send(:parse, File.read(filename))
|
|
28
39
|
else
|
|
29
|
-
Generator.send(:new, &block)
|
|
40
|
+
Generator.send(:new, verbose:, &block)
|
|
30
41
|
end
|
|
31
42
|
generator.output_context_size
|
|
32
43
|
generator.context
|
|
@@ -39,11 +50,15 @@ module ContextSpook
|
|
|
39
50
|
class Generator
|
|
40
51
|
private_class_method :new
|
|
41
52
|
|
|
42
|
-
# The initialize method sets up the object by evaluating the provided block
|
|
53
|
+
# The initialize method sets up the object by evaluating the provided block
|
|
54
|
+
# in the object's context.
|
|
43
55
|
#
|
|
44
|
-
# @param
|
|
56
|
+
# @param verbose [ TrueClass, FalseClass ] flag to enable verbose
|
|
57
|
+
# output during processing, defaults to lfalse.
|
|
58
|
+
# @param block [ Proc ] a block of code to be evaluated within the object's context
|
|
45
59
|
# If no block is given, the method does nothing.
|
|
46
|
-
def initialize(&block)
|
|
60
|
+
def initialize(verbose: false, &block)
|
|
61
|
+
@verbose = verbose
|
|
47
62
|
block and instance_eval(&block)
|
|
48
63
|
end
|
|
49
64
|
|
|
@@ -72,7 +87,9 @@ module ContextSpook
|
|
|
72
87
|
json_content_size = Tins::Unit.format(
|
|
73
88
|
context_size, format: '%.2f %U', unit: ?b, prefix: 1024
|
|
74
89
|
)
|
|
75
|
-
|
|
90
|
+
if @verbose
|
|
91
|
+
STDERR.puts "Built #{json_content_size} of JSON context in total."
|
|
92
|
+
end
|
|
76
93
|
end
|
|
77
94
|
|
|
78
95
|
# The Context class represents and manages project context data, providing
|
|
@@ -156,10 +173,14 @@ module ContextSpook
|
|
|
156
173
|
file_size = Tins::Unit.format(
|
|
157
174
|
File.size(filename), format: '%.2f %U', unit: ?b, prefix: 1024
|
|
158
175
|
)
|
|
159
|
-
|
|
176
|
+
if @verbose
|
|
177
|
+
STDERR.puts "Read #{filename.inspect} as JSON (%s) for context." % file_size
|
|
178
|
+
end
|
|
160
179
|
JSON.load_file(filename)
|
|
161
180
|
rescue Errno::ENOENT => e
|
|
162
|
-
|
|
181
|
+
if @verbose
|
|
182
|
+
STDERR.puts color(208) { "Reading #{filename.inspect} as JSON caused #{e.class}: #{e}" }
|
|
183
|
+
end
|
|
163
184
|
nil
|
|
164
185
|
end
|
|
165
186
|
|
|
@@ -193,10 +214,14 @@ module ContextSpook
|
|
|
193
214
|
file_size = Tins::Unit.format(
|
|
194
215
|
content.size, format: '%.2f %U', unit: ?b, prefix: 1024
|
|
195
216
|
)
|
|
196
|
-
|
|
217
|
+
if @verbose
|
|
218
|
+
STDERR.puts "Read #{filename.inspect} (%s) for context." % file_size
|
|
219
|
+
end
|
|
197
220
|
nil
|
|
198
221
|
rescue Errno::ENOENT => e
|
|
199
|
-
|
|
222
|
+
if @verbose
|
|
223
|
+
STDERR.puts color(208) { "Reading #{filename.inspect} caused #{e.class}: #{e}" }
|
|
224
|
+
end
|
|
200
225
|
end
|
|
201
226
|
|
|
202
227
|
# The commands method sets up a DSL accessor for provided command outputs.
|
|
@@ -219,7 +244,11 @@ module ContextSpook
|
|
|
219
244
|
output = `#{shell_command}`
|
|
220
245
|
exit_code = $?&.exitstatus.to_i
|
|
221
246
|
if exit_code != 0
|
|
222
|
-
|
|
247
|
+
if @verbose
|
|
248
|
+
STDERR.puts color(208) {
|
|
249
|
+
"Executing #{shell_command.inspect} resulted in exit code #{exit_code}."
|
|
250
|
+
}
|
|
251
|
+
end
|
|
223
252
|
end
|
|
224
253
|
commands[shell_command] = {
|
|
225
254
|
namespace: scope_top,
|
|
@@ -231,23 +260,28 @@ module ContextSpook
|
|
|
231
260
|
output_size = Tins::Unit.format(
|
|
232
261
|
output.size, format: '%.2f %U', unit: ?b, prefix: 1024
|
|
233
262
|
)
|
|
234
|
-
|
|
263
|
+
if @verbose
|
|
264
|
+
STDERR.puts "Executed #{shell_command.inspect} with output (%s) for context." % output_size
|
|
265
|
+
end
|
|
235
266
|
nil
|
|
236
267
|
end
|
|
237
268
|
|
|
238
269
|
# The to_json method converts the object to a JSON representation by
|
|
239
270
|
# first generating its hash form and then serializing that hash into JSON
|
|
240
271
|
# format.
|
|
272
|
+
#
|
|
273
|
+
# @param args [ Array ] pass-through arguments
|
|
241
274
|
memoize method:
|
|
242
|
-
def to_json(*)
|
|
243
|
-
as_json.to_json(*)
|
|
275
|
+
def to_json(*args)
|
|
276
|
+
as_json.to_json(*args)
|
|
244
277
|
end
|
|
245
278
|
|
|
246
279
|
# The as_json method converts the context's files, commands, and metadata
|
|
247
280
|
# into a hash representation.
|
|
248
281
|
#
|
|
282
|
+
# @param ignored [ Array ] ignored arguments
|
|
249
283
|
# @return [ Hash ] a hash containing the files, commands, and metadata
|
|
250
|
-
def as_json(*)
|
|
284
|
+
def as_json(*ignored)
|
|
251
285
|
{
|
|
252
286
|
files:,
|
|
253
287
|
commands:,
|
|
@@ -2,7 +2,7 @@ require 'spec_helper'
|
|
|
2
2
|
|
|
3
3
|
describe ContextSpook::Generator do
|
|
4
4
|
let :context do
|
|
5
|
-
ContextSpook.generate_context('contexts/project.rb')
|
|
5
|
+
ContextSpook.generate_context('.contexts/project.rb')
|
|
6
6
|
end
|
|
7
7
|
|
|
8
8
|
it 'context can be generated from block' do
|
|
@@ -34,7 +34,7 @@ describe ContextSpook::Generator do
|
|
|
34
34
|
|
|
35
35
|
it 'cannot do from block and filename' do
|
|
36
36
|
expect {
|
|
37
|
-
ContextSpook.generate_context('contexts/project.rb') { }
|
|
37
|
+
ContextSpook.generate_context('.contexts/project.rb') { }
|
|
38
38
|
}.to raise_error(ArgumentError, /need either a filename or a &block/)
|
|
39
39
|
end
|
|
40
40
|
|
|
@@ -64,7 +64,7 @@ describe ContextSpook::Generator do
|
|
|
64
64
|
command = context.commands['tree']
|
|
65
65
|
expect(command).to be_present
|
|
66
66
|
expect(command[:working_directory]).to eq Dir.pwd
|
|
67
|
-
expect(command[:exit_code]).
|
|
67
|
+
expect(command[:exit_code]).not_to be_nil
|
|
68
68
|
if command[:exit_code] == 0
|
|
69
69
|
expect(command[:output]).to be_present
|
|
70
70
|
else
|
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.
|
|
4
|
+
version: 0.5.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.8'
|
|
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.8'
|
|
26
26
|
- !ruby/object:Gem::Dependency
|
|
27
27
|
name: all_images
|
|
28
28
|
requirement: !ruby/object:Gem::Requirement
|
|
@@ -162,13 +162,13 @@ extra_rdoc_files:
|
|
|
162
162
|
- lib/context_spook/generator.rb
|
|
163
163
|
- lib/context_spook/version.rb
|
|
164
164
|
files:
|
|
165
|
+
- ".contexts/project.rb"
|
|
165
166
|
- Gemfile
|
|
166
167
|
- LICENSE
|
|
167
168
|
- README.md
|
|
168
169
|
- Rakefile
|
|
169
170
|
- bin/context_spook
|
|
170
171
|
- context_spook.gemspec
|
|
171
|
-
- contexts/project.rb
|
|
172
172
|
- hello_world.json
|
|
173
173
|
- lib/context_spook.rb
|
|
174
174
|
- lib/context_spook/generator.rb
|
|
@@ -197,7 +197,7 @@ required_rubygems_version: !ruby/object:Gem::Requirement
|
|
|
197
197
|
- !ruby/object:Gem::Version
|
|
198
198
|
version: '0'
|
|
199
199
|
requirements: []
|
|
200
|
-
rubygems_version: 3.
|
|
200
|
+
rubygems_version: 3.7.2
|
|
201
201
|
specification_version: 4
|
|
202
202
|
summary: context_spook collects project context for AI
|
|
203
203
|
test_files:
|