ace-handbook 0.19.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.
Files changed (85) hide show
  1. checksums.yaml +7 -0
  2. data/.ace-defaults/handbook/config.yml +4 -0
  3. data/.ace-defaults/nav/protocols/guide-sources/ace-handbook.yml +19 -0
  4. data/.ace-defaults/nav/protocols/tmpl-sources/ace-handbook.yml +10 -0
  5. data/.ace-defaults/nav/protocols/wfi-sources/ace-handbook.yml +19 -0
  6. data/CHANGELOG.md +362 -0
  7. data/LICENSE +21 -0
  8. data/README.md +42 -0
  9. data/Rakefile +12 -0
  10. data/exe/ace-handbook +6 -0
  11. data/handbook/guides/ai-agent-integration.g.md +625 -0
  12. data/handbook/guides/atom-pattern.g.md +371 -0
  13. data/handbook/guides/changelog.g.md +333 -0
  14. data/handbook/guides/cli-dry-cli.g.md +276 -0
  15. data/handbook/guides/cli-support-cli.g.md +277 -0
  16. data/handbook/guides/coding-standards/ruby.md +41 -0
  17. data/handbook/guides/coding-standards/rust.md +19 -0
  18. data/handbook/guides/coding-standards/typescript.md +20 -0
  19. data/handbook/guides/coding-standards.g.md +134 -0
  20. data/handbook/guides/debug-troubleshooting.g.md +62 -0
  21. data/handbook/guides/error-handling/ruby.md +29 -0
  22. data/handbook/guides/error-handling/rust.md +59 -0
  23. data/handbook/guides/error-handling/typescript.md +38 -0
  24. data/handbook/guides/error-handling.g.md +207 -0
  25. data/handbook/guides/meta/agents-definition.g.md +823 -0
  26. data/handbook/guides/meta/guides-definition.g.md +322 -0
  27. data/handbook/guides/meta/markdown-definition.g.md +210 -0
  28. data/handbook/guides/meta/tools-definition.g.md +159 -0
  29. data/handbook/guides/meta/workflow-instructions-definition.g.md +367 -0
  30. data/handbook/guides/mono-repo-patterns.g.md +92 -0
  31. data/handbook/guides/multi-agent-research.g.md +251 -0
  32. data/handbook/guides/performance/ruby.md +25 -0
  33. data/handbook/guides/performance/rust.md +48 -0
  34. data/handbook/guides/performance/typescript.md +32 -0
  35. data/handbook/guides/performance.g.md +211 -0
  36. data/handbook/guides/prompt-caching.g.md +83 -0
  37. data/handbook/guides/quality-assurance/ruby.md +33 -0
  38. data/handbook/guides/quality-assurance/rust.md +41 -0
  39. data/handbook/guides/quality-assurance/typescript.md +49 -0
  40. data/handbook/guides/quality-assurance.g.md +222 -0
  41. data/handbook/guides/strategic-planning.g.md +69 -0
  42. data/handbook/guides/troubleshooting/ruby.md +21 -0
  43. data/handbook/guides/troubleshooting/rust.md +20 -0
  44. data/handbook/guides/troubleshooting/typescript.md +36 -0
  45. data/handbook/guides/workflow-context-embedding.g.md +286 -0
  46. data/handbook/skills/as-handbook-init-project/SKILL.md +34 -0
  47. data/handbook/skills/as-handbook-manage-agents/SKILL.md +35 -0
  48. data/handbook/skills/as-handbook-manage-guides/SKILL.md +35 -0
  49. data/handbook/skills/as-handbook-manage-workflows/SKILL.md +35 -0
  50. data/handbook/skills/as-handbook-parallel-research/SKILL.md +29 -0
  51. data/handbook/skills/as-handbook-perform-delivery/SKILL.md +35 -0
  52. data/handbook/skills/as-handbook-review-guides/SKILL.md +32 -0
  53. data/handbook/skills/as-handbook-review-workflows/SKILL.md +32 -0
  54. data/handbook/skills/as-handbook-synthesize-research/SKILL.md +29 -0
  55. data/handbook/skills/as-handbook-update-docs/SKILL.md +35 -0
  56. data/handbook/skills/as-release/SKILL.md +50 -0
  57. data/handbook/skills/as-release-bump-version/SKILL.md +28 -0
  58. data/handbook/skills/as-release-rubygems-publish/SKILL.md +58 -0
  59. data/handbook/skills/as-release-update-changelog/SKILL.md +28 -0
  60. data/handbook/templates/completed-work-documentation.md +59 -0
  61. data/handbook/templates/cookbooks/cookbook.template.md +237 -0
  62. data/handbook/templates/research-comparison.template.md +175 -0
  63. data/handbook/workflow-instructions/handbook/init-project.wf.md +629 -0
  64. data/handbook/workflow-instructions/handbook/manage-agents.wf.md +379 -0
  65. data/handbook/workflow-instructions/handbook/manage-guides.wf.md +294 -0
  66. data/handbook/workflow-instructions/handbook/manage-workflows.wf.md +292 -0
  67. data/handbook/workflow-instructions/handbook/parallel-research.wf.md +328 -0
  68. data/handbook/workflow-instructions/handbook/perform-delivery.wf.md +267 -0
  69. data/handbook/workflow-instructions/handbook/research.wf.md +247 -0
  70. data/handbook/workflow-instructions/handbook/review-guides.wf.md +348 -0
  71. data/handbook/workflow-instructions/handbook/review-workflows.wf.md +299 -0
  72. data/handbook/workflow-instructions/handbook/synthesize-research.wf.md +429 -0
  73. data/handbook/workflow-instructions/handbook/update-docs.wf.md +338 -0
  74. data/lib/ace/handbook/atoms/provider_registry.rb +70 -0
  75. data/lib/ace/handbook/cli/commands/status.rb +36 -0
  76. data/lib/ace/handbook/cli/commands/sync.rb +36 -0
  77. data/lib/ace/handbook/cli.rb +51 -0
  78. data/lib/ace/handbook/models/skill_document.rb +25 -0
  79. data/lib/ace/handbook/molecules/skill_projection.rb +54 -0
  80. data/lib/ace/handbook/organisms/provider_syncer.rb +106 -0
  81. data/lib/ace/handbook/organisms/skill_inventory.rb +54 -0
  82. data/lib/ace/handbook/organisms/status_collector.rb +181 -0
  83. data/lib/ace/handbook/version.rb +7 -0
  84. data/lib/ace/handbook.rb +28 -0
  85. metadata +227 -0
@@ -0,0 +1,338 @@
1
+ ---
2
+ doc-type: workflow
3
+ title: Update Handbook Documentation Workflow
4
+ purpose: Documentation for ace-handbook/handbook/workflow-instructions/handbook/update-docs.wf.md
5
+ ace-docs:
6
+ last-updated: 2026-03-12
7
+ last-checked: 2026-03-21
8
+ ---
9
+
10
+ # Update Handbook Documentation Workflow
11
+
12
+ ## Goal
13
+
14
+ Maintain accurate, comprehensive, and well-structured README documentation across ace-* packages
15
+ to ensure all components are properly documented and discoverable.
16
+
17
+ ## Prerequisites
18
+
19
+ * Understanding of handbook structure and component relationships
20
+ * Access to ace-* package directories
21
+ * Familiarity with handbook conventions and patterns
22
+ * Knowledge of commands, guides, workflows, and provider-agent integrations
23
+
24
+ ## Project Context Loading
25
+
26
+ ### Load project context preset
27
+
28
+ ace-bundle project
29
+ {: .language-bash}
30
+
31
+ ### Review target documentation files
32
+
33
+ * README.md (main handbook documentation)
34
+ * Provider integration READMEs when skills/projections are described
35
+ * Related package READMEs under `ace-*/README.md`
36
+
37
+ ### Understand handbook standards
38
+
39
+ * ace-handbook/handbook/guides/meta/guides-definition.g.md
40
+ * ace-handbook/handbook/guides/meta/workflow-instructions-definition.g.md
41
+ * ace-handbook/handbook/guides/meta/agents-definition.g.md
42
+
43
+ ## Process Steps
44
+
45
+ ### 1. Audit Current Documentation State
46
+
47
+ **For each README file:**
48
+
49
+ * Compare documented items against actual directory contents
50
+ * Identify missing, outdated, or incorrect information
51
+ * Check for broken links and invalid references
52
+ * Note structural inconsistencies
53
+
54
+ **Validation Commands:**
55
+
56
+ # Check for undocumented guides
57
+ for guide in guides/*.g.md; do
58
+ basename "$guide" | xargs -I {} grep -q {} README.md || echo "Missing: {}"
59
+ done
60
+
61
+ # Check for undocumented workflows
62
+ for wf in workflow-instructions/*.wf.md; do
63
+ basename "$wf" | xargs -I {} grep -q {} README.md || echo "Missing workflow: {}"
64
+ done
65
+
66
+ # Check for broken links
67
+ grep -o '\[.*\](.*.md)' README.md | grep -o '(.*\.md)' | tr -d '()' | while read link; do
68
+ [ -f "$link" ] || echo "Broken link: $link"
69
+ done
70
+ {: .language-bash}
71
+
72
+ ### 2. Update Main Handbook README
73
+
74
+ **Structure to maintain:**
75
+
76
+ # ACE Handbooks (ace-* packages)
77
+
78
+ [Brief description and purpose]
79
+
80
+ ## Quick Start
81
+ [Installation instructions]
82
+
83
+ ## Structure
84
+ [Directory organization]
85
+
86
+ ## Development Guides
87
+ ### [Category]
88
+ - [Guide links with descriptions]
89
+
90
+ ## Workflow Instructions
91
+ [Key workflows listed]
92
+
93
+ ## Templates
94
+ [Available templates]
95
+
96
+ ## Integrations
97
+ [AI assistant integrations]
98
+
99
+ ## Contributing
100
+ [How to contribute]
101
+ {: .language-markdown}
102
+
103
+ **Update Process:**
104
+
105
+ * Scan `guides/` directory for all `.g.md` files
106
+ * Group guides by category (Core Process, Technical Standards, Language-Specific, etc.)
107
+ * Update guide links with consistent format: `[Guide Name](path) | [Related Guide](path)`
108
+ * Include brief inline descriptions where helpful
109
+ * Maintain alphabetical ordering within categories
110
+
111
+ ### 3. Update Meta Documentation README
112
+
113
+ **Focus Areas:**
114
+
115
+ * `/gds` - Guide Definition Standards listings
116
+ * `/wfi` - Meta Workflow Instructions catalog
117
+ * `/tpl` - Template inventory
118
+ * Relationship diagrams showing how meta components interact
119
+ * Quick reference table for finding the right meta resource
120
+
121
+ **Structure Template:**
122
+
123
+ # Meta Documentation (`.meta`)
124
+
125
+ [Purpose and overview]
126
+
127
+ ## Structure
128
+
129
+ ### `/gds` - Guide Definition Standards
130
+ [List all definition files with descriptions]
131
+
132
+ ### `/wfi` - Meta Workflow Instructions
133
+ [Categorized workflow listings]
134
+
135
+ ### `/tpl` - Templates
136
+ [Template inventory with use cases]
137
+
138
+ ## Relationships
139
+ [ASCII diagram or structured explanation]
140
+
141
+ ## Usage
142
+ [Common tasks and how to accomplish them]
143
+
144
+ ## Quick Reference
145
+ [Table mapping needs to resources]
146
+ {: .language-markdown}
147
+
148
+ ### 4. Update Integrations README
149
+
150
+ **Key Sections to Maintain:**
151
+
152
+ * Current integration status (Claude Code, others)
153
+ * Directory structure with file counts
154
+ * Agent catalog with descriptions and links
155
+ * Command inventory (custom vs generated)
156
+ * Installation instructions
157
+ * Maintenance procedures
158
+ * Relationship dependencies
159
+
160
+ **Update Checklist:**
161
+
162
+ # Count agents
163
+ ls -1 .claude/agents/*.ag.md | wc -l
164
+
165
+ # Count commands
166
+ ls -1 dev-tools/commands/_custom/*.md | wc -l
167
+ ls -1 dev-tools/commands/_generated/*.md | wc -l
168
+
169
+ # Verify agent links
170
+ for agent in .claude/agents/*.ag.md; do
171
+ name=$(basename "$agent" .ag.md)
172
+ grep -q "$name" .integrations/README.md || echo "Missing agent doc: $name"
173
+ done
174
+ {: .language-bash}
175
+
176
+ ### 5. Synchronize Cross-References
177
+
178
+ **Ensure consistency across:**
179
+
180
+ * Links between README files
181
+ * References to guides, workflows, and templates
182
+ * Agent and command documentation
183
+ * Version numbers and counts
184
+ * Directory structure descriptions
185
+
186
+ **Cross-reference validation:**
187
+
188
+ # Check that all workflows mentioned in READMEs exist
189
+ grep -h "\.wf\.md" README.md .meta/README.md |
190
+ grep -o '[a-z-]*\.wf\.md' | sort -u | while read wf; do
191
+ find . -name "$wf" | grep -q . || echo "Referenced but missing: $wf"
192
+ done
193
+ {: .language-bash}
194
+
195
+ ### 6. Update Quick Reference Tables
196
+
197
+ **For each README, maintain tables for:**
198
+
199
+ * Component counts (guides, workflows, agents, commands)
200
+ * Category mappings
201
+ * Tool/workflow/guide relationships
202
+ * Common task → resource mappings
203
+
204
+ **Table Format:**
205
+
206
+ | Type | Count | Location | Definition |
207
+ |------|-------|----------|------------|
208
+ | Guides | XX | guides/ | .meta/gds/guides-definition.g.md |
209
+ | Workflows | XX | workflow-instructions/ | .meta/gds/workflow-instructions-definition.g.md |
210
+ | Agents | XX | .integrations/claude/agents/ | .meta/gds/agents-definition.g.md |
211
+ {: .language-markdown}
212
+
213
+ ## Embedded Templates
214
+
215
+ <templates>
216
+ <template path="readme-section-template.md">
217
+ ## [Section Name]
218
+
219
+ [Brief description of section purpose]
220
+
221
+ ### Available [Items]
222
+
223
+ **[Category]:**
224
+ - **[Item Name](./path/to/item.md)** - [One-line description]
225
+ - **[Item Name](./path/to/item.md)** - [One-line description]
226
+
227
+ **[Another Category]:**
228
+ - **[Item Name](./path/to/item.md)** - [One-line description]
229
+
230
+ ### Usage
231
+
232
+ ```bash
233
+ # Example command or workflow invocation
234
+ ```
235
+
236
+ ### Related Resources
237
+ - [Related Section](#section-anchor)
238
+ - [External Doc](./path/to/doc.md)
239
+ </template>
240
+
241
+ <template path="relationship-diagram-template.md">
242
+ ## Relationships
243
+
244
+ ```
245
+ Component A provides [what] for →
246
+ └─ Component B (specific items)
247
+ └─ Component C (specific items)
248
+
249
+ Component B maintains →
250
+ └─ Component D via [mechanism]
251
+ └─ Component E via [mechanism]
252
+ ```
253
+
254
+ ### Dependencies
255
+ - **[Component]** requires **[Other Component]** for [purpose]
256
+ - **[Component]** generates **[Output]** used by **[Consumer]**
257
+ </template>
258
+ </templates>
259
+
260
+ ## Validation Checklist
261
+
262
+ ### Content Accuracy
263
+
264
+ * All existing files are documented
265
+ * No references to deleted files
266
+ * Counts and statistics are current
267
+ * Categories match actual content
268
+
269
+
270
+ ### Link Integrity
271
+
272
+ * All internal links resolve correctly
273
+ * Relative paths are accurate
274
+ * No broken anchor links
275
+ * Cross-references between READMEs work
276
+
277
+
278
+ ### Structure Consistency
279
+
280
+ * Consistent heading hierarchy
281
+ * Uniform list formatting
282
+ * Table formatting matches standards
283
+ * Code block syntax highlighting
284
+
285
+
286
+ ### Completeness
287
+
288
+ * All directories have README files
289
+ * New components are documented
290
+ * Deprecated items are marked or removed
291
+ * Examples and usage instructions included
292
+
293
+
294
+ ## Success Criteria
295
+
296
+ * All README files accurately reflect current directory contents
297
+ * No broken links or missing references
298
+ * Consistent formatting and structure across all documentation
299
+ * Clear navigation paths between related components
300
+ * Quick reference sections enable fast discovery
301
+ * Counts and statistics are accurate
302
+ * Relationship diagrams correctly show dependencies
303
+
304
+ ## Error Handling
305
+
306
+ **Missing Files:**
307
+
308
+ * **Symptoms:** Documentation references non-existent files
309
+ * **Solution:** Either remove reference or locate/recreate missing file
310
+
311
+ **Inconsistent Information:**
312
+
313
+ * **Symptoms:** Same item described differently in multiple places
314
+ * **Solution:** Standardize description and update all references
315
+
316
+ **Broken Links:**
317
+
318
+ * **Symptoms:** Links return 404 or point to wrong location
319
+ * **Solution:** Update paths or find correct targets
320
+
321
+ **Outdated Counts:**
322
+
323
+ * **Symptoms:** Documented counts don't match actual files
324
+ * **Solution:** Recount and update all statistics
325
+
326
+ ## Usage Example
327
+
328
+ > "Update the handbook documentation after adding new workflow instructions and agents"
329
+
330
+ Following this workflow would:
331
+
332
+ 1. Audit current state of all three README files
333
+ 2. Update main README with new workflow listings
334
+ 3. Update meta README if meta-workflows were added
335
+ 4. Update integrations README with new agent information
336
+ 5. Synchronize all cross-references
337
+ 6. Update quick reference tables with new counts
338
+ 7. Validate all changes for accuracy and completeness
@@ -0,0 +1,70 @@
1
+ # frozen_string_literal: true
2
+
3
+ require "date"
4
+ require "yaml"
5
+
6
+ module Ace
7
+ module Handbook
8
+ module Atoms
9
+ class ProviderRegistry
10
+ LOCAL_MANIFEST_GLOB = File.join(
11
+ "ace-handbook-integration-*",
12
+ ".ace-defaults",
13
+ "handbook",
14
+ "providers",
15
+ "*.yml"
16
+ ).freeze
17
+
18
+ attr_reader :project_root
19
+
20
+ def initialize(project_root: Ace::Handbook.project_root)
21
+ @project_root = project_root
22
+ end
23
+
24
+ def providers
25
+ manifests.keys.sort
26
+ end
27
+
28
+ def known?(provider)
29
+ manifests.key?(provider.to_s)
30
+ end
31
+
32
+ def manifest(provider)
33
+ manifests.fetch(provider.to_s)
34
+ end
35
+
36
+ def output_dir(provider)
37
+ manifest(provider).fetch("output_dir")
38
+ end
39
+
40
+ def manifests
41
+ @manifests ||= begin
42
+ all_paths = local_manifest_paths + installed_manifest_paths
43
+
44
+ all_paths.each_with_object({}) do |path, manifests|
45
+ data = YAML.safe_load_file(path, permitted_classes: [Date, Time], aliases: true) || {}
46
+ provider = (data["provider"] || File.basename(path, ".yml")).to_s
47
+ next if provider.empty?
48
+
49
+ manifests[provider] ||= data.merge("_manifest_path" => path)
50
+ end
51
+ end
52
+ end
53
+
54
+ private
55
+
56
+ def local_manifest_paths
57
+ Dir.glob(File.join(project_root, LOCAL_MANIFEST_GLOB)).sort
58
+ end
59
+
60
+ def installed_manifest_paths
61
+ Gem::Specification.find_all.filter_map do |spec|
62
+ next unless spec.name.start_with?("ace-handbook-integration-")
63
+
64
+ Dir.glob(File.join(spec.full_gem_path, ".ace-defaults", "handbook", "providers", "*.yml"))
65
+ end.flatten.sort
66
+ end
67
+ end
68
+ end
69
+ end
70
+ end
@@ -0,0 +1,36 @@
1
+ # frozen_string_literal: true
2
+
3
+ module Ace
4
+ module Handbook
5
+ module CLI
6
+ module Commands
7
+ class Status < Ace::Support::Cli::Command
8
+ include Ace::Support::Cli::Base
9
+
10
+ desc "Show handbook provider integration status"
11
+
12
+ option :provider, aliases: ["-p"], desc: "Limit status to a single provider"
13
+ option :format, default: "table", desc: "Output format (table, json)"
14
+
15
+ def initialize(collector: nil)
16
+ super()
17
+ @collector = collector || Ace::Handbook::Organisms::StatusCollector.new
18
+ end
19
+
20
+ def call(provider: nil, format: "table", **)
21
+ snapshot = @collector.collect(provider: provider)
22
+
23
+ if format == "json"
24
+ puts JSON.pretty_generate(snapshot)
25
+ return
26
+ end
27
+
28
+ puts @collector.to_table(snapshot)
29
+ rescue => e
30
+ raise Ace::Support::Cli::Error.new(e.message)
31
+ end
32
+ end
33
+ end
34
+ end
35
+ end
36
+ end
@@ -0,0 +1,36 @@
1
+ # frozen_string_literal: true
2
+
3
+ module Ace
4
+ module Handbook
5
+ module CLI
6
+ module Commands
7
+ class Sync < Ace::Support::Cli::Command
8
+ include Ace::Support::Cli::Base
9
+
10
+ desc "Project canonical handbook skills into provider-native folders"
11
+
12
+ option :provider, aliases: ["-p"], desc: "Limit sync to a single provider"
13
+ option :quiet, aliases: ["-q"], type: :boolean, default: false, desc: "Suppress sync summary output"
14
+
15
+ def initialize(syncer: nil)
16
+ super()
17
+ @syncer = syncer || Ace::Handbook::Organisms::ProviderSyncer.new
18
+ end
19
+
20
+ def call(provider: nil, quiet: false, **)
21
+ results = @syncer.sync(provider: provider)
22
+ return if quiet
23
+
24
+ results.each do |result|
25
+ puts "synced #{result[:provider]} -> #{result[:relative_output_dir]} " \
26
+ "(#{result[:projected_skills]} skills, #{result[:updated_files]} updated, " \
27
+ "#{result[:removed_entries]} removed)"
28
+ end
29
+ rescue => e
30
+ raise Ace::Support::Cli::Error.new(e.message)
31
+ end
32
+ end
33
+ end
34
+ end
35
+ end
36
+ end
@@ -0,0 +1,51 @@
1
+ # frozen_string_literal: true
2
+
3
+ require "json"
4
+ require "ace/support/cli"
5
+ require "ace/core"
6
+
7
+ require_relative "../handbook"
8
+ require_relative "cli/commands/sync"
9
+ require_relative "cli/commands/status"
10
+
11
+ module Ace
12
+ module Handbook
13
+ module CLI
14
+ extend Ace::Support::Cli::RegistryDsl
15
+
16
+ PROGRAM_NAME = "ace-handbook"
17
+
18
+ REGISTERED_COMMANDS = [
19
+ ["sync", "Project canonical skills into provider-native folders"],
20
+ ["status", "Show handbook provider integration status"]
21
+ ].freeze
22
+
23
+ HELP_EXAMPLES = [
24
+ "ace-handbook sync # Sync all enabled providers",
25
+ "ace-handbook sync --provider pi # Sync only Pi",
26
+ "ace-handbook status # Show provider status",
27
+ "ace-handbook status --provider pi # Show Pi status"
28
+ ].freeze
29
+
30
+ register "sync", Commands::Sync
31
+ register "status", Commands::Status
32
+
33
+ version_cmd = Ace::Support::Cli::VersionCommand.build(
34
+ gem_name: "ace-handbook",
35
+ version: Ace::Handbook::VERSION
36
+ )
37
+ register "version", version_cmd
38
+ register "--version", version_cmd
39
+
40
+ help_cmd = Ace::Support::Cli::HelpCommand.build(
41
+ program_name: PROGRAM_NAME,
42
+ version: Ace::Handbook::VERSION,
43
+ commands: REGISTERED_COMMANDS,
44
+ examples: HELP_EXAMPLES
45
+ )
46
+ register "help", help_cmd
47
+ register "--help", help_cmd
48
+ register "-h", help_cmd
49
+ end
50
+ end
51
+ end
@@ -0,0 +1,25 @@
1
+ # frozen_string_literal: true
2
+
3
+ module Ace
4
+ module Handbook
5
+ module Models
6
+ class SkillDocument
7
+ attr_reader :source_path, :frontmatter, :body
8
+
9
+ def initialize(source_path:, frontmatter:, body:)
10
+ @source_path = source_path
11
+ @frontmatter = frontmatter
12
+ @body = body
13
+ end
14
+
15
+ def name
16
+ frontmatter.fetch("name")
17
+ end
18
+
19
+ def source
20
+ frontmatter.fetch("source", "unknown").to_s
21
+ end
22
+ end
23
+ end
24
+ end
25
+ end
@@ -0,0 +1,54 @@
1
+ # frozen_string_literal: true
2
+
3
+ require "yaml"
4
+
5
+ module Ace
6
+ module Handbook
7
+ module Molecules
8
+ class SkillProjection
9
+ class << self
10
+ def projection_targets(frontmatter, registry:)
11
+ integration = frontmatter.fetch("integration", {})
12
+ targets = integration["targets"]
13
+ return registry.providers if targets.nil? || targets.empty?
14
+
15
+ Array(targets).map(&:to_s).select { |provider| registry.known?(provider) }
16
+ end
17
+
18
+ def projected_frontmatter(frontmatter, provider:)
19
+ merged = deep_copy(frontmatter)
20
+ integration = merged.delete("integration") || {}
21
+ provider_meta = integration.fetch("providers", {}).fetch(provider.to_s, {})
22
+ overrides = provider_meta["frontmatter"] || {}
23
+
24
+ deep_merge(merged, overrides)
25
+ end
26
+
27
+ def render(frontmatter, body)
28
+ yaml = YAML.dump(frontmatter).sub(/\A---\n/, "")
29
+ normalized_body = body.to_s.sub(/\A\n+/, "")
30
+ ["---\n", yaml, "---\n\n", normalized_body].join.rstrip + "\n"
31
+ end
32
+
33
+ private
34
+
35
+ def deep_copy(data)
36
+ Marshal.load(Marshal.dump(data))
37
+ end
38
+
39
+ def deep_merge(base, overrides)
40
+ return overrides unless base.is_a?(Hash) && overrides.is_a?(Hash)
41
+
42
+ base.merge(overrides) do |_key, old_value, new_value|
43
+ if old_value.is_a?(Hash) && new_value.is_a?(Hash)
44
+ deep_merge(old_value, new_value)
45
+ else
46
+ new_value
47
+ end
48
+ end
49
+ end
50
+ end
51
+ end
52
+ end
53
+ end
54
+ end