prompt_manager 1.0.2 → 1.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/CHANGELOG.md +138 -27
- data/README.md +127 -271
- data/lib/pm/configuration.rb +34 -4
- data/lib/pm/core_directives.rb +21 -20
- data/lib/pm/directive.rb +26 -34
- data/lib/pm/directives.rb +55 -16
- data/lib/pm/errors.rb +71 -0
- data/lib/pm/metadata.rb +110 -9
- data/lib/pm/parsed.rb +51 -46
- data/lib/pm/render_scope.rb +74 -0
- data/lib/pm/renderer.rb +59 -0
- data/lib/pm/shell.rb +95 -40
- data/lib/pm/version.rb +1 -1
- data/lib/pm.rb +116 -57
- data/lib/prompt_manager.rb +6 -0
- metadata +13 -113
- data/.envrc +0 -3
- data/.irbrc +0 -14
- data/COMMITS.md +0 -196
- data/Rakefile +0 -12
- data/docs/api/configuration.md +0 -59
- data/docs/api/constants.md +0 -60
- data/docs/api/index.md +0 -14
- data/docs/api/metadata.md +0 -99
- data/docs/api/parsed.md +0 -98
- data/docs/api/pm-module.md +0 -169
- data/docs/api/render-context.md +0 -51
- data/docs/architecture/design-decisions.md +0 -70
- data/docs/architecture/index.md +0 -6
- data/docs/architecture/processing-pipeline.md +0 -112
- data/docs/assets/css/custom.css +0 -1
- data/docs/assets/images/prompt_manager.gif +0 -0
- data/docs/assets/images/prompt_manager.mp4 +0 -0
- data/docs/examples/ai-agent-prompts.md +0 -173
- data/docs/examples/code-review-prompt.md +0 -107
- data/docs/examples/index.md +0 -7
- data/docs/examples/multi-file-composition.md +0 -123
- data/docs/getting-started/configuration.md +0 -106
- data/docs/getting-started/index.md +0 -7
- data/docs/getting-started/installation.md +0 -34
- data/docs/getting-started/quick-start.md +0 -94
- data/docs/guides/comment-stripping.md +0 -64
- data/docs/guides/custom-directives.md +0 -180
- data/docs/guides/erb-rendering.md +0 -102
- data/docs/guides/includes.md +0 -184
- data/docs/guides/index.md +0 -11
- data/docs/guides/parameters.md +0 -96
- data/docs/guides/parsing.md +0 -151
- data/docs/guides/shell-expansion.md +0 -108
- data/docs/index.md +0 -70
- data/mkdocs.yml +0 -181
data/lib/pm/shell.rb
CHANGED
|
@@ -1,57 +1,112 @@
|
|
|
1
1
|
# frozen_string_literal: true
|
|
2
2
|
|
|
3
3
|
require 'open3'
|
|
4
|
+
require 'strscan'
|
|
4
5
|
|
|
5
6
|
module PM
|
|
6
|
-
# Expands shell references in a string
|
|
7
|
-
#
|
|
8
|
-
#
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
|
|
7
|
+
# Expands shell references in a string in a single left-to-right pass:
|
|
8
|
+
#
|
|
9
|
+
# $(command) -- replaced with the command's stdout (trailing newline removed)
|
|
10
|
+
# $VAR, ${VAR} -- replaced with the environment variable (UPPERCASE names only; "" if unset)
|
|
11
|
+
# \$ -- a literal dollar sign; the backslash is removed
|
|
12
|
+
#
|
|
13
|
+
# Command output is spliced in verbatim and never re-scanned, so a `$VAR` or
|
|
14
|
+
# `$(...)` that a command prints stays literal. With `erb_safe: true` any
|
|
15
|
+
# `<%` in command output is written as `<%%`, which ERB renders as a literal
|
|
16
|
+
# `<%`, so output cannot inject Ruby into a later ERB pass.
|
|
17
|
+
#
|
|
18
|
+
# Fenced code blocks (lines starting with ``` or ~~~) are copied through
|
|
19
|
+
# untouched: a prompt can show shell syntax to the model without running it.
|
|
20
|
+
#
|
|
21
|
+
# Raises PM::ShellExpansionError for an unmatched `$(` and
|
|
22
|
+
# PM::ShellCommandError when a command exits non-zero.
|
|
23
|
+
def self.expand_shell(string, erb_safe: false)
|
|
24
|
+
ShellExpander.new(string, erb_safe: erb_safe).expand
|
|
12
25
|
end
|
|
13
26
|
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
|
|
27
|
+
class ShellExpander
|
|
28
|
+
FENCE_OPEN_REGEXP = /[ ]{0,3}(`{3,}|~{3,})[^\n]*(?:\n|\z)/
|
|
29
|
+
LINE_REGEXP = /[^\n]*(?:\n|\z)/
|
|
30
|
+
ESCAPED_DOLLAR = /\\\$/
|
|
31
|
+
COMMAND_OPEN = /\$\(/
|
|
19
32
|
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
|
|
33
|
+
def initialize(string, erb_safe: false)
|
|
34
|
+
@scanner = StringScanner.new(string)
|
|
35
|
+
@erb_safe = erb_safe
|
|
36
|
+
end
|
|
23
37
|
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
end
|
|
38
|
+
def expand
|
|
39
|
+
out = +''
|
|
40
|
+
at_line_start = true
|
|
41
|
+
|
|
42
|
+
until @scanner.eos?
|
|
43
|
+
if at_line_start && (fence = @scanner.scan(FENCE_OPEN_REGEXP))
|
|
44
|
+
out << fence << copy_fenced_block(fence)
|
|
45
|
+
elsif @scanner.scan(ESCAPED_DOLLAR)
|
|
46
|
+
out << '$'
|
|
47
|
+
elsif @scanner.scan(COMMAND_OPEN)
|
|
48
|
+
out << run_command
|
|
49
|
+
elsif @scanner.scan(ENV_VAR_REGEXP)
|
|
50
|
+
out << ENV.fetch(@scanner[1] || @scanner[2], '')
|
|
51
|
+
else
|
|
52
|
+
out << @scanner.getch
|
|
40
53
|
end
|
|
41
|
-
|
|
54
|
+
|
|
55
|
+
at_line_start = out.end_with?("\n")
|
|
42
56
|
end
|
|
43
57
|
|
|
44
|
-
|
|
58
|
+
out
|
|
45
59
|
end
|
|
46
60
|
|
|
47
|
-
|
|
48
|
-
|
|
49
|
-
|
|
61
|
+
private
|
|
62
|
+
|
|
63
|
+
# Copies lines verbatim up to and including the closing fence (or end of input).
|
|
64
|
+
def copy_fenced_block(open_line)
|
|
65
|
+
marker = open_line[/`{3,}|~{3,}/]
|
|
66
|
+
close = /\A[ ]{0,3}#{Regexp.escape(marker[0])}{#{marker.length},}[ \t]*(?:\n|\z)\z/
|
|
67
|
+
out = +''
|
|
68
|
+
|
|
69
|
+
until @scanner.eos?
|
|
70
|
+
line = @scanner.scan(LINE_REGEXP)
|
|
71
|
+
out << line
|
|
72
|
+
break if line.match?(close)
|
|
73
|
+
end
|
|
74
|
+
|
|
75
|
+
out
|
|
76
|
+
end
|
|
77
|
+
|
|
78
|
+
# Called with the scanner positioned just after "$(". Finds the matching
|
|
79
|
+
# ")" (honouring nested parentheses), runs the command, and returns its stdout.
|
|
80
|
+
def run_command
|
|
81
|
+
command = read_command
|
|
82
|
+
output, stderr, status = Open3.capture3(command)
|
|
50
83
|
|
|
51
|
-
|
|
52
|
-
|
|
53
|
-
|
|
54
|
-
|
|
84
|
+
raise ShellCommandError.new(command, status, stderr) unless status.success?
|
|
85
|
+
|
|
86
|
+
$stderr.write(stderr) unless stderr.empty? # keep warnings visible, as with 1.0.x
|
|
87
|
+
output = output.chomp
|
|
88
|
+
output = output.gsub('<%', '<%%') if @erb_safe
|
|
89
|
+
output
|
|
90
|
+
end
|
|
91
|
+
|
|
92
|
+
def read_command
|
|
93
|
+
depth = 1
|
|
94
|
+
command = +''
|
|
95
|
+
|
|
96
|
+
until @scanner.eos?
|
|
97
|
+
char = @scanner.getch
|
|
98
|
+
if char == '('
|
|
99
|
+
depth += 1
|
|
100
|
+
elsif char == ')'
|
|
101
|
+
depth -= 1
|
|
102
|
+
break if depth.zero?
|
|
103
|
+
end
|
|
104
|
+
command << char
|
|
105
|
+
end
|
|
106
|
+
|
|
107
|
+
raise ShellExpansionError, "Unmatched $( in shell expansion: $(#{command}" unless depth.zero?
|
|
108
|
+
|
|
109
|
+
command
|
|
110
|
+
end
|
|
55
111
|
end
|
|
56
|
-
private_class_method :expand_env_vars
|
|
57
112
|
end
|
data/lib/pm/version.rb
CHANGED
data/lib/pm.rb
CHANGED
|
@@ -4,8 +4,11 @@ require 'date'
|
|
|
4
4
|
require 'pathname'
|
|
5
5
|
require 'yaml'
|
|
6
6
|
|
|
7
|
-
# PM (PromptManager) parses YAML
|
|
8
|
-
#
|
|
7
|
+
# PM (PromptManager) parses YAML front matter from markdown strings or files.
|
|
8
|
+
# Pipeline: strip HTML comments → extract metadata → shell expansion → ERB on demand (#to_s).
|
|
9
|
+
#
|
|
10
|
+
# Not thread-safe: PM.config and the directive registry are process-wide state.
|
|
11
|
+
# Configure and register directives at boot, then parse and render from any thread.
|
|
9
12
|
module PM
|
|
10
13
|
METADATA_REGEXP = /
|
|
11
14
|
\A
|
|
@@ -19,8 +22,13 @@ module PM
|
|
|
19
22
|
/mx
|
|
20
23
|
|
|
21
24
|
HTML_COMMENT_REGEXP = /<!--.*?-->/m
|
|
22
|
-
ENV_VAR_REGEXP
|
|
23
|
-
COMMAND_START
|
|
25
|
+
ENV_VAR_REGEXP = /\$\{([A-Z_][A-Z0-9_]*)\}|\$([A-Z_][A-Z0-9_]*)/
|
|
26
|
+
COMMAND_START = '$('
|
|
27
|
+
|
|
28
|
+
# Front-matter keys that control the pipeline and must be true/false.
|
|
29
|
+
FLAG_KEYS = %w[shell erb].freeze
|
|
30
|
+
TRUE_WORDS = %w[true yes on].freeze
|
|
31
|
+
FALSE_WORDS = %w[false no off].freeze
|
|
24
32
|
|
|
25
33
|
def self.config
|
|
26
34
|
@config ||= Configuration.new
|
|
@@ -28,99 +36,150 @@ module PM
|
|
|
28
36
|
|
|
29
37
|
def self.configure
|
|
30
38
|
yield config
|
|
39
|
+
config
|
|
31
40
|
end
|
|
32
41
|
|
|
33
42
|
# --- Parsing ---
|
|
34
43
|
|
|
35
|
-
# Parses a source through the full pipeline
|
|
36
|
-
#
|
|
44
|
+
# Parses a source through the full pipeline.
|
|
45
|
+
#
|
|
46
|
+
# When source is a Pathname, responds to :to_path, is a String ending in
|
|
47
|
+
# ".md", a Symbol, or a single word (e.g. "greeting"), it is treated as a
|
|
48
|
+
# file path. Symbols and single-word strings become "name.md" basenames.
|
|
49
|
+
# Relative paths are resolved against PM.config.prompts_dir. The file is
|
|
50
|
+
# read and `directory`, `name`, `created_at`, `modified_at` are added to
|
|
51
|
+
# the metadata.
|
|
37
52
|
#
|
|
38
|
-
#
|
|
39
|
-
# in ".md", a Symbol, or a single word (e.g. "greeting"), it is treated
|
|
40
|
-
# as a file path. Symbols and single-word strings are converted to
|
|
41
|
-
# "name.md" basenames. The file is read and parsed, and `directory`,
|
|
42
|
-
# `name`, `created_at`, `modified_at` are added to metadata.
|
|
53
|
+
# Otherwise source is parsed directly as a string (see .parse_string).
|
|
43
54
|
#
|
|
44
|
-
#
|
|
55
|
+
# Raises Errno::ENOENT when the file does not exist.
|
|
45
56
|
def self.parse(source)
|
|
46
57
|
source = "#{source}.md" if source.is_a?(Symbol) || single_word?(source)
|
|
47
|
-
|
|
48
|
-
|
|
49
|
-
|
|
50
|
-
|
|
51
|
-
|
|
52
|
-
|
|
53
|
-
|
|
54
|
-
parsed
|
|
55
|
-
|
|
56
|
-
|
|
57
|
-
|
|
58
|
-
|
|
59
|
-
directory: File.dirname(path),
|
|
60
|
-
name: File.basename(path),
|
|
61
|
-
created_at: stat.birthtime,
|
|
62
|
-
modified_at: stat.mtime
|
|
63
|
-
)
|
|
58
|
+
return parse_string(source) unless file_source?(source)
|
|
59
|
+
|
|
60
|
+
path = resolve_path(source)
|
|
61
|
+
parsed = parse_string(File.read(path))
|
|
62
|
+
stat = File.stat(path)
|
|
63
|
+
|
|
64
|
+
metadata = build_metadata(
|
|
65
|
+
parsed.metadata.to_h.merge(
|
|
66
|
+
directory: File.dirname(path),
|
|
67
|
+
name: File.basename(path),
|
|
68
|
+
created_at: birthtime(stat),
|
|
69
|
+
modified_at: stat.mtime
|
|
64
70
|
)
|
|
65
|
-
|
|
71
|
+
)
|
|
72
|
+
Parsed.new(metadata: metadata, content: parsed.content)
|
|
73
|
+
end
|
|
74
|
+
|
|
75
|
+
# Parses a string, never treating it as a file name.
|
|
76
|
+
#
|
|
77
|
+
# Raises PM::MetadataError when the front matter is not a YAML mapping, or
|
|
78
|
+
# when `shell`, `erb`, or `parameters` have values of the wrong type.
|
|
79
|
+
# YAML syntax errors raise Psych::SyntaxError.
|
|
80
|
+
def self.parse_string(string)
|
|
81
|
+
stripped = strip_comments(string)
|
|
82
|
+
match = stripped.match(METADATA_REGEXP)
|
|
83
|
+
|
|
84
|
+
if match
|
|
85
|
+
metadata = build_metadata(load_front_matter(match[:metadata]))
|
|
86
|
+
content = match[:content]
|
|
66
87
|
else
|
|
67
|
-
|
|
88
|
+
metadata = build_metadata({})
|
|
89
|
+
content = stripped
|
|
68
90
|
end
|
|
91
|
+
|
|
92
|
+
content = expand_shell(content, erb_safe: metadata.erb?) if metadata.shell?
|
|
93
|
+
|
|
94
|
+
Parsed.new(metadata: metadata, content: content)
|
|
69
95
|
end
|
|
70
96
|
|
|
71
|
-
#
|
|
97
|
+
# Strips HTML comments from a string.
|
|
98
|
+
def self.strip_comments(string)
|
|
99
|
+
string.gsub(HTML_COMMENT_REGEXP, '')
|
|
100
|
+
end
|
|
101
|
+
|
|
102
|
+
# --- Internals ---
|
|
103
|
+
|
|
72
104
|
def self.file_source?(source)
|
|
73
105
|
source.respond_to?(:to_path) || (source.is_a?(String) && source.end_with?('.md'))
|
|
74
106
|
end
|
|
75
107
|
private_class_method :file_source?
|
|
76
108
|
|
|
77
|
-
#
|
|
78
|
-
# path separators, or file extension.
|
|
109
|
+
# True when source is a single word: no spaces, path separators, or extension.
|
|
79
110
|
def self.single_word?(source)
|
|
80
111
|
source.is_a?(String) && source.match?(/\A\w+\z/)
|
|
81
112
|
end
|
|
82
113
|
private_class_method :single_word?
|
|
83
114
|
|
|
84
|
-
|
|
85
|
-
|
|
86
|
-
|
|
87
|
-
|
|
88
|
-
|
|
89
|
-
|
|
90
|
-
|
|
91
|
-
|
|
92
|
-
|
|
93
|
-
|
|
94
|
-
|
|
95
|
-
|
|
115
|
+
def self.resolve_path(source)
|
|
116
|
+
raw = source.respond_to?(:to_path) ? source.to_path : source
|
|
117
|
+
raw = (Pathname.new(config.prompts_dir) + raw).to_s unless config.prompts_dir.empty?
|
|
118
|
+
File.expand_path(raw)
|
|
119
|
+
end
|
|
120
|
+
private_class_method :resolve_path
|
|
121
|
+
|
|
122
|
+
# File creation time, falling back to ctime where the platform or
|
|
123
|
+
# filesystem has no birthtime (several Linux filesystems, containers).
|
|
124
|
+
def self.birthtime(stat)
|
|
125
|
+
stat.birthtime
|
|
126
|
+
rescue NotImplementedError, NoMethodError
|
|
127
|
+
stat.ctime
|
|
128
|
+
end
|
|
129
|
+
private_class_method :birthtime
|
|
96
130
|
|
|
97
|
-
|
|
131
|
+
def self.load_front_matter(yaml)
|
|
132
|
+
data = YAML.safe_load(yaml, permitted_classes: [Date, Time])
|
|
133
|
+
return {} if data.nil?
|
|
134
|
+
raise MetadataError, "Front matter must be a YAML mapping, got #{data.class}" unless data.is_a?(Hash)
|
|
98
135
|
|
|
99
|
-
|
|
136
|
+
data
|
|
100
137
|
end
|
|
138
|
+
private_class_method :load_front_matter
|
|
101
139
|
|
|
102
|
-
|
|
103
|
-
#
|
|
140
|
+
# Builds Metadata with `shell` and `erb` resolved against the global config
|
|
141
|
+
# (the file wins unless the config is locked) and the `parameters` type checked.
|
|
104
142
|
def self.build_metadata(hash)
|
|
105
|
-
|
|
106
|
-
|
|
143
|
+
attrs = hash.transform_keys(&:to_s)
|
|
144
|
+
|
|
145
|
+
FLAG_KEYS.each do |key|
|
|
146
|
+
global = config.public_send(key)
|
|
147
|
+
value = attrs[key]
|
|
148
|
+
attrs[key] = config.locked? || value.nil? ? global : coerce_flag(key, value)
|
|
149
|
+
end
|
|
150
|
+
|
|
151
|
+
params = attrs['parameters']
|
|
152
|
+
unless params.nil? || params.is_a?(Hash)
|
|
153
|
+
raise MetadataError, "parameters must be a mapping, got #{params.class}"
|
|
154
|
+
end
|
|
155
|
+
|
|
156
|
+
Metadata.new(attrs)
|
|
107
157
|
end
|
|
108
158
|
private_class_method :build_metadata
|
|
109
159
|
|
|
110
|
-
|
|
111
|
-
|
|
112
|
-
|
|
160
|
+
def self.coerce_flag(key, value)
|
|
161
|
+
return value if value.equal?(true) || value.equal?(false)
|
|
162
|
+
|
|
163
|
+
word = value.to_s.strip.downcase
|
|
164
|
+
return true if TRUE_WORDS.include?(word)
|
|
165
|
+
return false if FALSE_WORDS.include?(word)
|
|
166
|
+
|
|
167
|
+
raise MetadataError, "#{key} must be true or false, got #{value.inspect}"
|
|
113
168
|
end
|
|
169
|
+
private_class_method :coerce_flag
|
|
114
170
|
end
|
|
115
171
|
|
|
116
|
-
require_relative 'pm/configuration'
|
|
117
172
|
require_relative 'pm/version'
|
|
173
|
+
require_relative 'pm/errors'
|
|
174
|
+
require_relative 'pm/configuration'
|
|
118
175
|
require_relative 'pm/metadata'
|
|
176
|
+
require_relative 'pm/render_scope'
|
|
177
|
+
require_relative 'pm/renderer'
|
|
119
178
|
require_relative 'pm/parsed'
|
|
179
|
+
require_relative 'pm/shell'
|
|
120
180
|
require_relative 'pm/directives'
|
|
121
181
|
require_relative 'pm/directive'
|
|
122
182
|
require_relative 'pm/core_directives'
|
|
123
|
-
require_relative 'pm/shell'
|
|
124
183
|
|
|
125
184
|
# Register built-in directives from PM::CoreDirectives
|
|
126
185
|
PM::Directive.register_all
|
data/lib/prompt_manager.rb
CHANGED
|
@@ -1,3 +1,9 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
# Entry point for `require 'prompt_manager'` (the gem name, which Bundler
|
|
4
|
+
# auto-requires). The library lives in the PM namespace; PromptManager is a
|
|
5
|
+
# namespace alias only. The 0.x PromptManager::Prompt / Storage API was
|
|
6
|
+
# removed in 1.0.0 and is not provided here.
|
|
1
7
|
require_relative 'pm'
|
|
2
8
|
|
|
3
9
|
PromptManager = PM
|
metadata
CHANGED
|
@@ -1,142 +1,40 @@
|
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
|
2
2
|
name: prompt_manager
|
|
3
3
|
version: !ruby/object:Gem::Version
|
|
4
|
-
version: 1.0
|
|
4
|
+
version: 1.2.0
|
|
5
5
|
platform: ruby
|
|
6
6
|
authors:
|
|
7
7
|
- Dewayne VanHoozer
|
|
8
8
|
bindir: bin
|
|
9
9
|
cert_chain: []
|
|
10
10
|
date: 1980-01-02 00:00:00.000000000 Z
|
|
11
|
-
dependencies:
|
|
12
|
-
- !ruby/object:Gem::Dependency
|
|
13
|
-
name: ostruct
|
|
14
|
-
requirement: !ruby/object:Gem::Requirement
|
|
15
|
-
requirements:
|
|
16
|
-
- - ">="
|
|
17
|
-
- !ruby/object:Gem::Version
|
|
18
|
-
version: '0'
|
|
19
|
-
type: :runtime
|
|
20
|
-
prerelease: false
|
|
21
|
-
version_requirements: !ruby/object:Gem::Requirement
|
|
22
|
-
requirements:
|
|
23
|
-
- - ">="
|
|
24
|
-
- !ruby/object:Gem::Version
|
|
25
|
-
version: '0'
|
|
26
|
-
- !ruby/object:Gem::Dependency
|
|
27
|
-
name: amazing_print
|
|
28
|
-
requirement: !ruby/object:Gem::Requirement
|
|
29
|
-
requirements:
|
|
30
|
-
- - ">="
|
|
31
|
-
- !ruby/object:Gem::Version
|
|
32
|
-
version: '0'
|
|
33
|
-
type: :development
|
|
34
|
-
prerelease: false
|
|
35
|
-
version_requirements: !ruby/object:Gem::Requirement
|
|
36
|
-
requirements:
|
|
37
|
-
- - ">="
|
|
38
|
-
- !ruby/object:Gem::Version
|
|
39
|
-
version: '0'
|
|
40
|
-
- !ruby/object:Gem::Dependency
|
|
41
|
-
name: debug_me
|
|
42
|
-
requirement: !ruby/object:Gem::Requirement
|
|
43
|
-
requirements:
|
|
44
|
-
- - ">="
|
|
45
|
-
- !ruby/object:Gem::Version
|
|
46
|
-
version: '0'
|
|
47
|
-
type: :development
|
|
48
|
-
prerelease: false
|
|
49
|
-
version_requirements: !ruby/object:Gem::Requirement
|
|
50
|
-
requirements:
|
|
51
|
-
- - ">="
|
|
52
|
-
- !ruby/object:Gem::Version
|
|
53
|
-
version: '0'
|
|
54
|
-
- !ruby/object:Gem::Dependency
|
|
55
|
-
name: minitest
|
|
56
|
-
requirement: !ruby/object:Gem::Requirement
|
|
57
|
-
requirements:
|
|
58
|
-
- - ">="
|
|
59
|
-
- !ruby/object:Gem::Version
|
|
60
|
-
version: '0'
|
|
61
|
-
type: :development
|
|
62
|
-
prerelease: false
|
|
63
|
-
version_requirements: !ruby/object:Gem::Requirement
|
|
64
|
-
requirements:
|
|
65
|
-
- - ">="
|
|
66
|
-
- !ruby/object:Gem::Version
|
|
67
|
-
version: '0'
|
|
68
|
-
- !ruby/object:Gem::Dependency
|
|
69
|
-
name: simplecov
|
|
70
|
-
requirement: !ruby/object:Gem::Requirement
|
|
71
|
-
requirements:
|
|
72
|
-
- - ">="
|
|
73
|
-
- !ruby/object:Gem::Version
|
|
74
|
-
version: '0'
|
|
75
|
-
type: :development
|
|
76
|
-
prerelease: false
|
|
77
|
-
version_requirements: !ruby/object:Gem::Requirement
|
|
78
|
-
requirements:
|
|
79
|
-
- - ">="
|
|
80
|
-
- !ruby/object:Gem::Version
|
|
81
|
-
version: '0'
|
|
11
|
+
dependencies: []
|
|
82
12
|
description: |
|
|
83
|
-
PM (PromptManager) parses YAML
|
|
84
|
-
It expands shell references, extracts metadata and content,
|
|
85
|
-
ERB
|
|
13
|
+
PM (PromptManager) parses YAML front matter from markdown strings or files.
|
|
14
|
+
It expands shell references, extracts metadata and content, composes prompts
|
|
15
|
+
from other files with include/insert directives, and renders ERB on demand.
|
|
86
16
|
email:
|
|
87
17
|
- dvanhoozer@gmail.com
|
|
88
18
|
executables: []
|
|
89
19
|
extensions: []
|
|
90
20
|
extra_rdoc_files: []
|
|
91
21
|
files:
|
|
92
|
-
- ".envrc"
|
|
93
|
-
- ".irbrc"
|
|
94
22
|
- CHANGELOG.md
|
|
95
|
-
- COMMITS.md
|
|
96
23
|
- LICENSE
|
|
97
24
|
- README.md
|
|
98
|
-
- Rakefile
|
|
99
|
-
- docs/api/configuration.md
|
|
100
|
-
- docs/api/constants.md
|
|
101
|
-
- docs/api/index.md
|
|
102
|
-
- docs/api/metadata.md
|
|
103
|
-
- docs/api/parsed.md
|
|
104
|
-
- docs/api/pm-module.md
|
|
105
|
-
- docs/api/render-context.md
|
|
106
|
-
- docs/architecture/design-decisions.md
|
|
107
|
-
- docs/architecture/index.md
|
|
108
|
-
- docs/architecture/processing-pipeline.md
|
|
109
|
-
- docs/assets/css/custom.css
|
|
110
|
-
- docs/assets/images/prompt_manager.gif
|
|
111
|
-
- docs/assets/images/prompt_manager.mp4
|
|
112
|
-
- docs/examples/ai-agent-prompts.md
|
|
113
|
-
- docs/examples/code-review-prompt.md
|
|
114
|
-
- docs/examples/index.md
|
|
115
|
-
- docs/examples/multi-file-composition.md
|
|
116
|
-
- docs/getting-started/configuration.md
|
|
117
|
-
- docs/getting-started/index.md
|
|
118
|
-
- docs/getting-started/installation.md
|
|
119
|
-
- docs/getting-started/quick-start.md
|
|
120
|
-
- docs/guides/comment-stripping.md
|
|
121
|
-
- docs/guides/custom-directives.md
|
|
122
|
-
- docs/guides/erb-rendering.md
|
|
123
|
-
- docs/guides/includes.md
|
|
124
|
-
- docs/guides/index.md
|
|
125
|
-
- docs/guides/parameters.md
|
|
126
|
-
- docs/guides/parsing.md
|
|
127
|
-
- docs/guides/shell-expansion.md
|
|
128
|
-
- docs/index.md
|
|
129
25
|
- lib/pm.rb
|
|
130
26
|
- lib/pm/configuration.rb
|
|
131
27
|
- lib/pm/core_directives.rb
|
|
132
28
|
- lib/pm/directive.rb
|
|
133
29
|
- lib/pm/directives.rb
|
|
30
|
+
- lib/pm/errors.rb
|
|
134
31
|
- lib/pm/metadata.rb
|
|
135
32
|
- lib/pm/parsed.rb
|
|
33
|
+
- lib/pm/render_scope.rb
|
|
34
|
+
- lib/pm/renderer.rb
|
|
136
35
|
- lib/pm/shell.rb
|
|
137
36
|
- lib/pm/version.rb
|
|
138
37
|
- lib/prompt_manager.rb
|
|
139
|
-
- mkdocs.yml
|
|
140
38
|
homepage: https://github.com/MadBomber/prompt_manager
|
|
141
39
|
licenses:
|
|
142
40
|
- MIT
|
|
@@ -144,7 +42,9 @@ metadata:
|
|
|
144
42
|
allowed_push_host: https://rubygems.org
|
|
145
43
|
homepage_uri: https://github.com/MadBomber/prompt_manager
|
|
146
44
|
source_code_uri: https://github.com/MadBomber/prompt_manager
|
|
147
|
-
changelog_uri: https://github.com/MadBomber/prompt_manager
|
|
45
|
+
changelog_uri: https://github.com/MadBomber/prompt_manager/blob/main/CHANGELOG.md
|
|
46
|
+
documentation_uri: https://madbomber.github.io/prompt_manager
|
|
47
|
+
bug_tracker_uri: https://github.com/MadBomber/prompt_manager/issues
|
|
148
48
|
rdoc_options: []
|
|
149
49
|
require_paths:
|
|
150
50
|
- lib
|
|
@@ -152,14 +52,14 @@ required_ruby_version: !ruby/object:Gem::Requirement
|
|
|
152
52
|
requirements:
|
|
153
53
|
- - ">="
|
|
154
54
|
- !ruby/object:Gem::Version
|
|
155
|
-
version:
|
|
55
|
+
version: 4.0.9
|
|
156
56
|
required_rubygems_version: !ruby/object:Gem::Requirement
|
|
157
57
|
requirements:
|
|
158
58
|
- - ">="
|
|
159
59
|
- !ruby/object:Gem::Version
|
|
160
60
|
version: '0'
|
|
161
61
|
requirements: []
|
|
162
|
-
rubygems_version: 4.0.
|
|
62
|
+
rubygems_version: 4.0.23
|
|
163
63
|
specification_version: 4
|
|
164
64
|
summary: Parse YAML metadata from markdown prompts with shell expansion and ERB rendering
|
|
165
65
|
test_files: []
|
data/.envrc
DELETED
data/.irbrc
DELETED
|
@@ -1,14 +0,0 @@
|
|
|
1
|
-
require_relative 'lib/prompt_manager'
|
|
2
|
-
require_relative 'lib/prompt_manager/storage/file_system_adapter'
|
|
3
|
-
|
|
4
|
-
HERE = Pathname.new __dir__
|
|
5
|
-
|
|
6
|
-
PromptManager::Storage::FileSystemAdapter.config do |config|
|
|
7
|
-
config.prompts_dir = HERE + 'examples/prompts_dir'
|
|
8
|
-
# config.search_proc = nil # default
|
|
9
|
-
# config.prompt_extension = '.txt' # default
|
|
10
|
-
# config.parms+_extension = '.json' # default
|
|
11
|
-
end
|
|
12
|
-
|
|
13
|
-
PromptManager::Prompt.storage_adapter = PromptManager::Storage::FileSystemAdapter.new
|
|
14
|
-
|