ace-docs 0.31.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 (91) hide show
  1. checksums.yaml +7 -0
  2. data/.ace-defaults/docs/config.yml +169 -0
  3. data/.ace-defaults/docs/multi-subject-example.md +130 -0
  4. data/.ace-defaults/docs/single-subject-example.md +150 -0
  5. data/.ace-defaults/nav/protocols/guide-sources/ace-docs.yml +10 -0
  6. data/.ace-defaults/nav/protocols/prompt-sources/ace-docs.yml +34 -0
  7. data/.ace-defaults/nav/protocols/tmpl-sources/ace-docs.yml +10 -0
  8. data/.ace-defaults/nav/protocols/wfi-sources/ace-docs.yml +19 -0
  9. data/CHANGELOG.md +1082 -0
  10. data/LICENSE +21 -0
  11. data/README.md +40 -0
  12. data/Rakefile +14 -0
  13. data/exe/ace-docs +14 -0
  14. data/handbook/guides/documentation/ruby.md +16 -0
  15. data/handbook/guides/documentation/rust.md +35 -0
  16. data/handbook/guides/documentation/typescript.md +18 -0
  17. data/handbook/guides/documentation.g.md +437 -0
  18. data/handbook/guides/documents-embedded-sync.g.md +473 -0
  19. data/handbook/guides/documents-embedding.g.md +276 -0
  20. data/handbook/guides/markdown-style.g.md +290 -0
  21. data/handbook/prompts/ace-change-analyzer.system.md +113 -0
  22. data/handbook/prompts/ace-change-analyzer.user.md +95 -0
  23. data/handbook/prompts/document-analysis.md +74 -0
  24. data/handbook/prompts/document-analysis.system.md +129 -0
  25. data/handbook/prompts/markdown-style.system.md +113 -0
  26. data/handbook/skills/as-docs-create-adr/SKILL.md +35 -0
  27. data/handbook/skills/as-docs-create-api/SKILL.md +35 -0
  28. data/handbook/skills/as-docs-create-user/SKILL.md +35 -0
  29. data/handbook/skills/as-docs-maintain-adrs/SKILL.md +35 -0
  30. data/handbook/skills/as-docs-squash-changelog/SKILL.md +42 -0
  31. data/handbook/skills/as-docs-update/SKILL.md +36 -0
  32. data/handbook/skills/as-docs-update-blueprint/SKILL.md +28 -0
  33. data/handbook/skills/as-docs-update-roadmap/SKILL.md +24 -0
  34. data/handbook/skills/as-docs-update-tools/SKILL.md +36 -0
  35. data/handbook/skills/as-docs-update-usage/SKILL.md +26 -0
  36. data/handbook/templates/code-docs/javascript-jsdoc.template.md +102 -0
  37. data/handbook/templates/code-docs/ruby-yard.template.md +85 -0
  38. data/handbook/templates/project-docs/README.template.md +73 -0
  39. data/handbook/templates/project-docs/architecture.template.md +300 -0
  40. data/handbook/templates/project-docs/blueprint.template.md +165 -0
  41. data/handbook/templates/project-docs/context/ownership.yml +160 -0
  42. data/handbook/templates/project-docs/decisions/adr.template.md +60 -0
  43. data/handbook/templates/project-docs/prd.template.md +144 -0
  44. data/handbook/templates/project-docs/roadmap/roadmap.template.md +47 -0
  45. data/handbook/templates/project-docs/vision.template.md +233 -0
  46. data/handbook/templates/user-docs/user-guide.template.md +107 -0
  47. data/handbook/workflow-instructions/docs/create-adr.wf.md +334 -0
  48. data/handbook/workflow-instructions/docs/create-api.wf.md +448 -0
  49. data/handbook/workflow-instructions/docs/create-cookbook.wf.md +434 -0
  50. data/handbook/workflow-instructions/docs/create-user.wf.md +399 -0
  51. data/handbook/workflow-instructions/docs/maintain-adrs.wf.md +589 -0
  52. data/handbook/workflow-instructions/docs/squash-changelog.wf.md +246 -0
  53. data/handbook/workflow-instructions/docs/update-blueprint.wf.md +361 -0
  54. data/handbook/workflow-instructions/docs/update-context.wf.md +336 -0
  55. data/handbook/workflow-instructions/docs/update-roadmap.wf.md +421 -0
  56. data/handbook/workflow-instructions/docs/update-tools.wf.md +307 -0
  57. data/handbook/workflow-instructions/docs/update-usage.wf.md +710 -0
  58. data/handbook/workflow-instructions/docs/update.wf.md +418 -0
  59. data/lib/ace/docs/atoms/diff_filterer.rb +131 -0
  60. data/lib/ace/docs/atoms/frontmatter_free_matcher.rb +20 -0
  61. data/lib/ace/docs/atoms/git_date_resolver.rb +16 -0
  62. data/lib/ace/docs/atoms/readme_metadata_inferrer.rb +60 -0
  63. data/lib/ace/docs/atoms/terminology_extractor.rb +308 -0
  64. data/lib/ace/docs/atoms/time_range_calculator.rb +96 -0
  65. data/lib/ace/docs/atoms/timestamp_parser.rb +106 -0
  66. data/lib/ace/docs/atoms/type_inferrer.rb +70 -0
  67. data/lib/ace/docs/cli/commands/analyze.rb +351 -0
  68. data/lib/ace/docs/cli/commands/analyze_consistency.rb +185 -0
  69. data/lib/ace/docs/cli/commands/discover.rb +75 -0
  70. data/lib/ace/docs/cli/commands/scope_options.rb +71 -0
  71. data/lib/ace/docs/cli/commands/status.rb +241 -0
  72. data/lib/ace/docs/cli/commands/update.rb +198 -0
  73. data/lib/ace/docs/cli/commands/validate.rb +225 -0
  74. data/lib/ace/docs/cli.rb +60 -0
  75. data/lib/ace/docs/models/analysis_report.rb +120 -0
  76. data/lib/ace/docs/models/consistency_report.rb +259 -0
  77. data/lib/ace/docs/models/document.rb +354 -0
  78. data/lib/ace/docs/molecules/change_detector.rb +389 -0
  79. data/lib/ace/docs/molecules/document_loader.rb +133 -0
  80. data/lib/ace/docs/molecules/frontmatter_manager.rb +85 -0
  81. data/lib/ace/docs/molecules/git_date_resolver.rb +30 -0
  82. data/lib/ace/docs/organisms/cross_document_analyzer.rb +274 -0
  83. data/lib/ace/docs/organisms/document_registry.rb +318 -0
  84. data/lib/ace/docs/organisms/validator.rb +164 -0
  85. data/lib/ace/docs/prompts/compact_diff_prompt.rb +119 -0
  86. data/lib/ace/docs/prompts/consistency_prompt.rb +286 -0
  87. data/lib/ace/docs/prompts/document_analysis_prompt.rb +389 -0
  88. data/lib/ace/docs/version.rb +7 -0
  89. data/lib/ace/docs.rb +82 -0
  90. data/lib/test.rb +4 -0
  91. metadata +347 -0
@@ -0,0 +1,418 @@
1
+ ---
2
+ doc-type: workflow
3
+ title: Update Documentation with ace-docs
4
+ purpose: Update documentation with ace-docs tool orchestration
5
+ ace-docs:
6
+ last-updated: 2026-03-08
7
+ last-checked: 2026-03-21
8
+ ---
9
+
10
+ # Update Documentation with ace-docs
11
+
12
+ Orchestrate ace-docs tools for iterative documentation updates through agent/human collaboration.
13
+
14
+ ## Quick Start
15
+
16
+ ### Specific File Update (Direct Path)
17
+
18
+ When updating a specific document, go straight to analysis:
19
+
20
+ ```bash
21
+ # Analyze specific document immediately
22
+ ace-docs analyze docs/api.md
23
+
24
+ # Review the analysis report
25
+ cat .ace-local/docs/analyze-*/analysis.md
26
+
27
+ # Update document based on recommendations
28
+ ace-docs update docs/api.md --set last-updated=today
29
+ ```
30
+
31
+ ### Bulk Update (Status Check First)
32
+
33
+ When updating multiple documents or checking what needs updates:
34
+
35
+ ```bash
36
+ # Check which documents need updates
37
+ ace-docs status --needs-update
38
+
39
+ # Analyze all documents needing updates
40
+ ace-docs analyze --needs-update
41
+
42
+ # Review analysis report and update documents
43
+ cat .ace-local/docs/analyze-*/analysis.md
44
+ ace-docs update [file] --set last-updated=today
45
+
46
+ # Or filter by type
47
+ ace-docs status --type guide
48
+ ace-docs analyze --all --type guide
49
+
50
+ # Scope to one package
51
+ ace-docs status --package ace-assign
52
+ ace-docs validate --package ace-assign --all
53
+
54
+ # Scope with glob (bare package path is normalized)
55
+ ace-docs status --glob ace-assign
56
+ ace-docs validate --glob "ace-assign/docs/**/*.md" --syntax
57
+ ```
58
+
59
+ ## Input Handling
60
+
61
+ Accept flexible input for document selection:
62
+
63
+ ### Direct Analysis (Skip Status Check)
64
+
65
+ When specific file(s) are provided, the workflow proceeds directly to analysis:
66
+
67
+ 1. **Specific documents**: List of file paths
68
+ - `docs/api.md handbook/guide.md`
69
+ - Goes straight to `ace-docs analyze [files]`
70
+
71
+ ### Status-First (Check What Needs Updates)
72
+
73
+ When using filters or bulk operations, the workflow starts with status check:
74
+
75
+ 2. **Preset selection**: Use configured preset
76
+ - `--preset standard`
77
+ 3. **Type filtering**: Update by document type
78
+ - `--type guide`
79
+ 4. **Scope filtering**: Restrict by package or path glob
80
+ - `--package ace-assign`
81
+ - `--glob ace-assign` (normalized to `ace-assign/**/*.md`)
82
+ - `--glob "ace-assign/docs/**/*.md"`
83
+ 5. **Status-based**: Documents needing update
84
+ - `--needs-update` (default when no files specified)
85
+ 6. **All documents**: Process everything
86
+ - `--all`
87
+
88
+ **Decision Rule**: If specific file paths are provided → skip to analysis. Otherwise → start with status check.
89
+
90
+ ## Workflow Steps
91
+
92
+ ### Decision Point: Specific File or Bulk Operation?
93
+
94
+ **If specific file(s) provided** → Skip to Step 2 (Analyze Documents)
95
+ **If bulk/filter operation** → Start at Step 1 (Load Document Status)
96
+
97
+ ### 1. Load Document Status (Bulk Operations Only)
98
+
99
+ **Skip this step if specific file(s) were provided.**
100
+
101
+ For bulk operations, check current state of managed documents:
102
+
103
+ ```bash
104
+ ace-docs status [options]
105
+ ```
106
+
107
+ Review the table showing:
108
+ - Document names and types
109
+ - Last updated dates
110
+ - Freshness status (current/stale/outdated)
111
+ - Update frequency configuration
112
+
113
+ If no documents match criteria, exit with message.
114
+
115
+ ### 2. Analyze Documents (Always Required)
116
+
117
+ Generate LLM-powered analysis for selected documents:
118
+
119
+ ```bash
120
+ ace-docs analyze [file|--all|--needs-update] [options]
121
+ ```
122
+
123
+ Options:
124
+ - `--since DATE`: Analyze from specific date/commit
125
+ - `--exclude-renames`: Skip renamed files
126
+ - `--exclude-moves`: Skip moved files
127
+
128
+ The analysis is saved to `.ace-local/docs/analyze-{timestamp}/analysis.md`
129
+
130
+ **Note**: The analyze directory contains additional files (context.md, *.diff, prompts) for debugging purposes only. The workflow uses `analysis.md` as the primary output.
131
+
132
+ **Decision Point**: If no changes detected, exit workflow.
133
+
134
+ ### 2.5 Review Analysis Report
135
+
136
+ Read the generated analysis report:
137
+
138
+ ```bash
139
+ cat .ace-local/docs/analyze-*/analysis.md
140
+ ```
141
+
142
+ The report contains:
143
+ - **Summary**: Overview of changes affecting the document
144
+ - **Changes Detected**: Categorized by priority (HIGH/MEDIUM/LOW)
145
+ - **Recommended Updates**: Specific sections to update with reasoning
146
+ - **Additional Notes**: Context and patterns to consider
147
+
148
+ Use these LLM recommendations to guide your document updates in the next step.
149
+
150
+ ### 3. Review and Update Documents
151
+
152
+ For each document with changes:
153
+
154
+ #### a. Load Document Context
155
+ - Read current document content
156
+ - Review frontmatter configuration
157
+ - Note update focus areas if specified
158
+
159
+ #### b. Apply Analysis Recommendations
160
+ Using the analysis.md report:
161
+ - Focus on HIGH priority changes first
162
+ - Review specific "Recommended Updates" for the document
163
+ - Consider the reasoning provided for each recommendation
164
+ - Maintain document style while incorporating changes
165
+
166
+ #### c. Update Document Content
167
+ **Agent/Human Decision**: Based on changes:
168
+ - Update technical details
169
+ - Add new sections
170
+ - Remove outdated information
171
+ - Maintain document style/voice
172
+
173
+ #### d. Update Metadata
174
+ After content updates:
175
+
176
+ ```bash
177
+ ace-docs update [file] --set last-updated=today --set last-checked=today
178
+ ```
179
+
180
+ Additional metadata updates:
181
+ - Version numbers if applicable
182
+ - Custom metadata fields
183
+ - Context requirements
184
+
185
+ ### 4. Validate Updates
186
+
187
+ Run validation on updated documents:
188
+
189
+ ```bash
190
+ ace-docs validate [file|pattern] [--syntax|--semantic|--all]
191
+ ```
192
+
193
+ Check for:
194
+ - Required frontmatter fields
195
+ - Max line limits
196
+ - Required sections
197
+ - Syntax errors (if linter available)
198
+ - Semantic issues (if LLM available)
199
+
200
+ ### 5. Present Summary
201
+
202
+ Generate summary of updates:
203
+ - Number of documents updated
204
+ - Types of changes made
205
+ - Any validation issues
206
+ - Documents skipped/deferred
207
+
208
+ ## Document-Specific Guidelines
209
+
210
+ ### Tool Documentation (tools.md, reference docs)
211
+
212
+ When updating tool documentation and command references:
213
+
214
+ **Best Practices for Examples:**
215
+ - Only include meaningful, practical examples that demonstrate real usage
216
+ - Skip trivial commands like `--version`, `--help`, `-h`, `-v`
217
+ - Show actual usage that demonstrates the tool's purpose
218
+ - Aim for 2-4 practical examples per tool
219
+ - Focus on common use cases and workflows
220
+
221
+ **Example - Good:**
222
+ ```bash
223
+ # Analyze documents needing updates
224
+ ace-docs status --needs-update
225
+
226
+ # Update specific document metadata
227
+ ace-docs update docs/api.md --set last-updated=today
228
+ ```
229
+
230
+ **Example - Skip:**
231
+ ```bash
232
+ ace-docs --version # Trivial, not useful
233
+ ace-docs -h # Help text, not practical usage
234
+ ```
235
+
236
+ ### Architecture Decision Records (ADRs)
237
+
238
+ For ADR lifecycle management (creation, evolution, archival, scope updates):
239
+
240
+ **Creating new ADRs:**
241
+ `wfi://docs/create-adr`
242
+
243
+ **Maintaining existing ADRs:**
244
+ `wfi://docs/maintain-adrs`
245
+
246
+ ADR maintenance includes:
247
+ - Evolution documentation when patterns change
248
+ - Archival of obsolete decisions
249
+ - Scope updates for partially outdated decisions
250
+ - Synchronization with `docs/decisions.md` summary
251
+
252
+ ### Context Documents (vision.md, architecture.md, etc.)
253
+
254
+ For core context documents with specific requirements (line limits, update order, duplication prevention), see the specialized workflow:
255
+
256
+ `wfi://docs/update-context`
257
+
258
+ This workflow provides:
259
+ - Specific update order to prevent duplication
260
+ - Target line counts for each document
261
+ - Content ownership rules
262
+ - Cross-document validation
263
+
264
+ ## Error Handling
265
+
266
+ - **Missing frontmatter**: Suggest adding ace-docs frontmatter
267
+ - **Validation failures**: Report specific issues, continue with other docs
268
+ - **Git errors**: Check repository state, suggest fixes
269
+ - **LLM unavailable**: The analyze command will fail - it requires LLM for generating recommendations
270
+ - **Empty analysis**: Check if document has subject configuration and if changes exist in the time period
271
+
272
+ ## Integration Points
273
+
274
+ ### With ace-bundle
275
+ Load project context for documentation:
276
+ ```bash
277
+ ace-bundle --preset docs
278
+ ```
279
+
280
+ ### With LLM Analysis
281
+ The `ace-docs analyze` command automatically integrates with LLM for intelligent change analysis. The `analysis.md` output provides:
282
+ - Prioritized changes (HIGH/MEDIUM/LOW)
283
+ - Specific recommendations for document updates
284
+ - Context-aware reasoning
285
+
286
+ No manual LLM integration is needed - it's built into the analyze command.
287
+
288
+ ### With git workflow
289
+ After updates, commit changes:
290
+ ```bash
291
+ git add [updated-files]
292
+ git commit -m "docs: Update documentation via ace-docs
293
+
294
+ - Updated [list of documents]
295
+ - Synchronized with recent changes
296
+ - Validated against configured rules"
297
+ ```
298
+
299
+ ## Configuration
300
+
301
+ ### Document Discovery
302
+ Configure in `.ace/docs/config.yml`:
303
+ ```yaml
304
+ document_types:
305
+ guide:
306
+ paths: ["**/*.g.md", "handbook/guides/**/*.md"]
307
+ defaults:
308
+ update_frequency: monthly
309
+ api:
310
+ paths: ["*/docs/api/*.md"]
311
+ defaults:
312
+ update_frequency: on-change
313
+ ```
314
+
315
+ ### Multi-Subject Configuration
316
+ Configure multiple subjects in document frontmatter for categorized analysis:
317
+ ```yaml
318
+ ace-docs:
319
+ subject:
320
+ - code:
321
+ diff:
322
+ paths: ["**/*.rb", "**/*.js"]
323
+ - config:
324
+ diff:
325
+ paths: ["**/*.yml", "**/*.yaml"]
326
+ - docs:
327
+ diff:
328
+ paths: ["**/*.md"]
329
+ ```
330
+
331
+ The `analyze` command will generate separate diffs for each subject, providing more focused analysis.
332
+
333
+ ### Global Rules
334
+ ```yaml
335
+ global_rules:
336
+ max_lines: 1000
337
+ required_frontmatter: ["doc-type", "purpose"]
338
+ ```
339
+
340
+ ## Exit Conditions
341
+
342
+ Workflow exits when:
343
+ - No documents match selection criteria
344
+ - No changes detected in diff analysis
345
+ - All selected documents processed
346
+ - Critical error prevents continuation
347
+
348
+ ## Usage Examples
349
+
350
+ ### Update specific document (Direct Path)
351
+ ```bash
352
+ # When you know exactly which document to update
353
+ # Skip status check and go straight to analysis
354
+ ace-docs analyze ace-docs/README.md
355
+
356
+ # Review the analysis report
357
+ cat .ace-local/docs/analyze-*/analysis.md
358
+
359
+ # Update document based on recommendations
360
+ # [Review analysis.md and update content]
361
+ ace-docs update ace-docs/README.md --set last-updated=today
362
+ ```
363
+
364
+ ### Update stale guides (Bulk Operation)
365
+ ```bash
366
+ # Start with status check for bulk operations
367
+ ace-docs status --type guide --freshness stale
368
+
369
+ # Analyze changes and generate recommendations
370
+ ace-docs analyze --type guide --freshness stale
371
+
372
+ # Review the analysis report
373
+ cat .ace-local/docs/analyze-*/analysis.md
374
+
375
+ # Update each document based on recommendations
376
+ # [Review analysis.md and update content]
377
+ ace-docs update guide1.md --set last-updated=today
378
+ ```
379
+
380
+ ### Bulk metadata update
381
+ ```bash
382
+ # Update all documents of a type
383
+ ace-docs update --preset standard --set version=2.0
384
+ ```
385
+
386
+ ### Pre-commit validation
387
+ ```bash
388
+ # Validate all changed documents
389
+ ace-docs validate $(git diff --name-only -- '*.md')
390
+ ```
391
+
392
+ ### Analyze and update workflow
393
+
394
+ #### For specific file (direct):
395
+ ```bash
396
+ # Direct analysis when you know the file
397
+ ace-docs analyze docs/architecture.md
398
+ cat .ace-local/docs/analyze-*/analysis.md
399
+ # Review recommendations and update document
400
+ ace-docs update docs/architecture.md --set last-updated=today
401
+ ```
402
+
403
+ #### For bulk updates (status-first):
404
+ ```bash
405
+ # Check what needs updating first
406
+ ace-docs status --needs-update
407
+ ace-docs analyze --needs-update
408
+ cat .ace-local/docs/analyze-*/analysis.md
409
+ # Review recommendations and update documents
410
+ ace-docs update [file] --set last-updated=today
411
+ ```
412
+
413
+ ## Notes
414
+
415
+ - The workflow is designed for iterative updates with human/agent oversight
416
+ - Change analysis provides data, but update decisions remain with the operator
417
+ - Metadata-only updates are safe and reversible
418
+ - Content updates should be reviewed before committing
@@ -0,0 +1,131 @@
1
+ # frozen_string_literal: true
2
+
3
+ module Ace
4
+ module Docs
5
+ module Atoms
6
+ # Pure functions for filtering diff content
7
+ class DiffFilterer
8
+ class << self
9
+ # Default patterns to exclude from diffs
10
+ DEFAULT_EXCLUDE_PATTERNS = [
11
+ %r{^test/},
12
+ %r{^spec/},
13
+ %r{\.test\.},
14
+ %r{\.spec\.},
15
+ %r{^coverage/},
16
+ %r{^tmp/},
17
+ %r{^vendor/},
18
+ %r{^node_modules/},
19
+ %r{^\.git/},
20
+ %r{Gemfile\.lock$},
21
+ %r{package-lock\.json$},
22
+ %r{yarn\.lock$}
23
+ ].freeze
24
+
25
+ # Filter paths from diff output
26
+ # @param diff [String] The diff content
27
+ # @param exclude_patterns [Array<Regexp>] Patterns to exclude
28
+ # @return [String] Filtered diff content
29
+ def filter_paths(diff, exclude_patterns = DEFAULT_EXCLUDE_PATTERNS)
30
+ return "" if diff.nil? || diff.empty?
31
+
32
+ lines = diff.split("\n")
33
+ filtered_lines = []
34
+ skip_until_next_file = false
35
+
36
+ lines.each do |line|
37
+ # Check if this is a file header
38
+ if file_header?(line)
39
+ file_path = extract_file_path(line)
40
+ if should_exclude?(file_path, exclude_patterns)
41
+ skip_until_next_file = true
42
+ else
43
+ skip_until_next_file = false
44
+ filtered_lines << line
45
+ end
46
+ elsif !skip_until_next_file
47
+ filtered_lines << line
48
+ end
49
+ end
50
+
51
+ filtered_lines.join("\n")
52
+ end
53
+
54
+ # Estimate the size of a diff in lines
55
+ # @param diff [String] The diff content
56
+ # @return [Integer] Number of lines
57
+ def estimate_size(diff)
58
+ return 0 if diff.nil? || diff.empty?
59
+
60
+ diff.count("\n") + 1
61
+ end
62
+
63
+ # Count significant changes (additions and deletions)
64
+ # @param diff [String] The diff content
65
+ # @return [Hash] Statistics about the diff
66
+ def count_changes(diff)
67
+ return {additions: 0, deletions: 0, files: 0} if diff.nil? || diff.empty?
68
+
69
+ additions = 0
70
+ deletions = 0
71
+ files = 0
72
+
73
+ diff.split("\n").each do |line|
74
+ if file_header?(line)
75
+ files += 1
76
+ elsif line.start_with?("+") && !line.start_with?("+++")
77
+ additions += 1
78
+ elsif line.start_with?("-") && !line.start_with?("---")
79
+ deletions += 1
80
+ end
81
+ end
82
+
83
+ {
84
+ additions: additions,
85
+ deletions: deletions,
86
+ files: files,
87
+ total_changes: additions + deletions
88
+ }
89
+ end
90
+
91
+ # Check if diff is too large for processing
92
+ # @param diff [String] The diff content
93
+ # @param max_lines [Integer] Maximum allowed lines
94
+ # @return [Boolean] True if diff exceeds limit
95
+ def exceeds_limit?(diff, max_lines = 100_000)
96
+ estimate_size(diff) > max_lines
97
+ end
98
+
99
+ private
100
+
101
+ # Check if a line is a file header in git diff format
102
+ def file_header?(line)
103
+ line.start_with?("diff --git", "+++", "---") ||
104
+ line.match?(/^index [a-f0-9]+\.\.[a-f0-9]+/)
105
+ end
106
+
107
+ # Extract file path from diff header line
108
+ def extract_file_path(line)
109
+ case line
110
+ when /^diff --git a\/(.+) b\/(.+)$/
111
+ Regexp.last_match(2) # Use the 'b/' path (new file path)
112
+ when /^\+\+\+ b\/(.+)$/
113
+ Regexp.last_match(1)
114
+ when /^--- a\/(.+)$/
115
+ Regexp.last_match(1)
116
+ else
117
+ ""
118
+ end
119
+ end
120
+
121
+ # Check if a file path should be excluded
122
+ def should_exclude?(file_path, patterns)
123
+ return false if file_path.empty?
124
+
125
+ patterns.any? { |pattern| file_path.match?(pattern) }
126
+ end
127
+ end
128
+ end
129
+ end
130
+ end
131
+ end
@@ -0,0 +1,20 @@
1
+ # frozen_string_literal: true
2
+
3
+ require "ace/core/molecules/frontmatter_free_policy"
4
+
5
+ module Ace
6
+ module Docs
7
+ module Atoms
8
+ # Matches markdown files that are managed without frontmatter.
9
+ class FrontmatterFreeMatcher
10
+ def self.match?(path, patterns:, project_root: Dir.pwd)
11
+ Ace::Core::Molecules::FrontmatterFreePolicy.match?(
12
+ path,
13
+ patterns: patterns,
14
+ project_root: project_root
15
+ )
16
+ end
17
+ end
18
+ end
19
+ end
20
+ end
@@ -0,0 +1,16 @@
1
+ # frozen_string_literal: true
2
+
3
+ require_relative "../molecules/git_date_resolver"
4
+
5
+ module Ace
6
+ module Docs
7
+ module Atoms
8
+ # Compatibility shim: delegated to molecule implementation.
9
+ class GitDateResolver
10
+ def self.last_updated_for(path)
11
+ Molecules::GitDateResolver.last_updated_for(path)
12
+ end
13
+ end
14
+ end
15
+ end
16
+ end
@@ -0,0 +1,60 @@
1
+ # frozen_string_literal: true
2
+
3
+ module Ace
4
+ module Docs
5
+ module Atoms
6
+ # Infers metadata for README files managed without frontmatter.
7
+ class ReadmeMetadataInferrer
8
+ def self.infer(path:, content:, last_updated: nil)
9
+ return nil unless File.basename(path).casecmp("README.md").zero?
10
+
11
+ title = extract_title(content, path)
12
+ parent = parent_label(path)
13
+ doc_type = root_readme?(path) ? "root_readme" : "readme"
14
+ purpose = if doc_type == "root_readme"
15
+ "Monorepo entry point and navigation for ACE"
16
+ else
17
+ "User-facing introduction for #{parent}"
18
+ end
19
+
20
+ metadata = {
21
+ "doc-type" => doc_type,
22
+ "purpose" => purpose,
23
+ "update" => {"frequency" => "on-change"}
24
+ }
25
+
26
+ if last_updated
27
+ metadata["ace-docs"] = {"last-updated" => last_updated.strftime("%Y-%m-%d")}
28
+ end
29
+
30
+ metadata["title"] = title
31
+ metadata
32
+ end
33
+
34
+ def self.extract_title(content, path)
35
+ match = content.to_s.match(/^#\s+([^\n]+)$/)
36
+ return match[1].strip if match
37
+
38
+ parent_label(path)
39
+ end
40
+ private_class_method :extract_title
41
+
42
+ def self.parent_label(path)
43
+ parent = File.basename(File.dirname(path.to_s))
44
+ (parent.nil? || parent.empty? || parent == ".") ? File.basename(Dir.pwd) : parent
45
+ end
46
+ private_class_method :parent_label
47
+
48
+ def self.root_readme?(path)
49
+ normalized = path.to_s.sub(%r{\A\./}, "")
50
+ return true if normalized.casecmp("README.md").zero?
51
+
52
+ File.expand_path(path.to_s) == File.join(Dir.pwd, "README.md")
53
+ rescue
54
+ false
55
+ end
56
+ private_class_method :root_readme?
57
+ end
58
+ end
59
+ end
60
+ end