appydave-tools 0.17.0 → 0.18.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 +22 -0
- data/CLAUDE.md +44 -7
- data/README.md +19 -7
- data/bin/{vat → dam} +163 -83
- data/docs/{vat → dam}/dam-vision.md +13 -13
- data/docs/dam/session-summary-2025-11-09.md +478 -0
- data/docs/{vat → dam}/usage.md +177 -86
- data/docs/{vat → dam}/vat-testing-plan.md +94 -94
- data/docs/development/CODEX-recommendations.md +204 -86
- data/lib/appydave/tools/configuration/models/brands_config.rb +18 -3
- data/lib/appydave/tools/{vat → dam}/config.rb +32 -13
- data/lib/appydave/tools/{vat → dam}/config_loader.rb +1 -1
- data/lib/appydave/tools/{vat → dam}/manifest_generator.rb +3 -3
- data/lib/appydave/tools/{vat → dam}/project_listing.rb +1 -1
- data/lib/appydave/tools/{vat → dam}/project_resolver.rb +1 -1
- data/lib/appydave/tools/{vat → dam}/s3_operations.rb +3 -3
- data/lib/appydave/tools/dam/sync_from_ssd.rb +241 -0
- data/lib/appydave/tools/version.rb +1 -1
- data/lib/appydave/tools.rb +7 -6
- data/package.json +1 -1
- metadata +14 -13
- data/docs/vat/session-summary-2025-11-09.md +0 -297
|
@@ -1,123 +1,241 @@
|
|
|
1
|
-
# CODEX Recommendations
|
|
1
|
+
# CODEX Recommendations - Review & Status
|
|
2
2
|
|
|
3
|
-
> Last updated: 2025-11-
|
|
4
|
-
>
|
|
3
|
+
> Last updated: 2025-11-10
|
|
4
|
+
> Original recommendations provided by Codex (GPT-5) on 2025-11-09
|
|
5
5
|
|
|
6
|
-
|
|
6
|
+
This document captures Codex's architectural recommendations with implementation status and verdicts after engineering review.
|
|
7
7
|
|
|
8
|
-
##
|
|
8
|
+
## Executive Summary
|
|
9
9
|
|
|
10
|
-
|
|
11
|
-
- **Secondary friction**: command classes mix terminal IO with core logic (see `lib/appydave/tools/vat/project_resolver.rb:19-50`), which complicates automation and reuse.
|
|
12
|
-
- **Tooling debt**: RuboCop is configured (`.rubocop.yml`) but not enforced; the current run emits 108 offenses (93 auto-correctable per Claude logs) and engineers silence cops instead of resolving root causes.
|
|
10
|
+
**Overall Assessment:** Mixed recommendations - some valuable, some outdated, some architecturally inappropriate.
|
|
13
11
|
|
|
14
|
-
|
|
12
|
+
**Implemented:** ✅ P3 (Filesystem fixtures)
|
|
13
|
+
**Rejected:** ❌ P0 (Configuration DI), P1 (RuboCop - already clean), P4 (method_missing removal)
|
|
14
|
+
**Deferred:** ⚠️ P2 (IO separation - CLI tool doesn't need it)
|
|
15
|
+
**Future Work:** 🔍 VAT Manifest bugs (valid technical debt)
|
|
15
16
|
|
|
16
|
-
|
|
17
|
-
| --- | --- | --- |
|
|
18
|
-
| P0 | Make configuration/services injectable | Unlocks clean tests, eliminates global stubs, and keeps future CLIs composable. |
|
|
19
|
-
| P1 | Re-enable effective lint/test automation | 93 auto-fixes are “free”; the remaining 15 surface real architecture problems that deserve explicit debt tracking. |
|
|
20
|
-
| P2 | Separate IO from business logic in CLI helpers | Enables automation agents (Claude) and humans to reuse services without TTY prompts. |
|
|
21
|
-
| P3 | Standardize filesystem fixtures | Reduces the bespoke `Dir.mktmpdir` + `FileUtils` boilerplate sprinkled through VAT specs; faster, safer tests. |
|
|
17
|
+
---
|
|
22
18
|
|
|
23
|
-
##
|
|
19
|
+
## Priority Recommendations
|
|
24
20
|
|
|
25
|
-
###
|
|
21
|
+
### ✅ P3: Standardize Filesystem Fixtures (IMPLEMENTED)
|
|
26
22
|
|
|
27
|
-
|
|
28
|
-
- **Action**:
|
|
29
|
-
1. Create a lightweight `SettingsProvider` (duck-typed or interface module) that exposes `video_projects_root`.
|
|
30
|
-
2. Update VAT entry points to accept `settings:` or `config:` keyword args defaulting to the singleton, e.g. `def projects_root(settings: default_settings)`.
|
|
31
|
-
3. Provide a `Config.with_settings(temp_settings) { ... }` helper for specs and CLI overrides.
|
|
32
|
-
- **Impact**: RSpec can inject fakes without `allow_any_instance_of`; RuboCop warning disappears with no cop disable required.
|
|
23
|
+
**Recommendation:** Extract `Dir.mktmpdir + FileUtils.mkdir_p` boilerplate into shared RSpec context.
|
|
33
24
|
|
|
34
|
-
|
|
25
|
+
**Status:** ✅ **Implemented** (2025-11-10)
|
|
35
26
|
|
|
36
|
-
|
|
37
|
-
-
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
-
|
|
27
|
+
**What was done:**
|
|
28
|
+
- Created `spec/support/vat_filesystem_helpers.rb` with shared contexts
|
|
29
|
+
- `include_context 'vat filesystem'` - provides temp_folder, projects_root, auto-cleanup
|
|
30
|
+
- `include_context 'vat filesystem with brands', brands: %w[appydave voz]` - adds brand path helpers
|
|
31
|
+
- Refactored 3 VAT specs: config_spec, project_resolver_spec, config_loader_spec
|
|
32
|
+
- All tests passing (149 examples, 0 failures)
|
|
42
33
|
|
|
43
|
-
|
|
34
|
+
**Benefits delivered:**
|
|
35
|
+
- Reduced duplication across VAT specs
|
|
36
|
+
- Centralized cleanup logic (safer tests)
|
|
37
|
+
- Easier to maintain and extend
|
|
44
38
|
|
|
45
|
-
|
|
46
|
-
- **Action**:
|
|
47
|
-
1. Extract the pure resolution logic so it always returns a result set (possibly multi-match) and never prints.
|
|
48
|
-
2. Create an `InteractiveResolver` (or CLI layer) that takes `io_in:`/`io_out:` and handles messaging/selection.
|
|
49
|
-
3. Update `bin/vat` commands to use the interactive wrapper; specs can cover both the pure resolver and the IO adapter with deterministic streams.
|
|
50
|
-
- **Bonus**: While refactoring, move the repeated `Dir.glob` filtering into a shared helper (e.g., `Projects::Scanner`) so CLAUDE/Code agents can reuse it for listing commands.
|
|
39
|
+
---
|
|
51
40
|
|
|
52
|
-
###
|
|
41
|
+
### ❌ P1: RuboCop Cleanup (ALREADY COMPLETE)
|
|
53
42
|
|
|
54
|
-
|
|
55
|
-
- **Action**:
|
|
56
|
-
1. Add `spec/support/filesystem_helpers.rb` with helpers like `with_projects_root(brands: %w[appydave]) { |root| ... }`.
|
|
57
|
-
2. Include the helper in `spec/spec_helper.rb`, then convert VAT specs to the helper to remove boilerplate and centralize cleanup.
|
|
58
|
-
3. Consider shipping seeded sample trees under `spec/samples/video-projects` for regression-style tests that need deeper structures.
|
|
43
|
+
**Recommendation:** Run `rubocop --auto-correct` to fix 93 offenses, track 15 manual fixes.
|
|
59
44
|
|
|
60
|
-
|
|
45
|
+
**Status:** ❌ **Obsolete** - RuboCop already clean
|
|
61
46
|
|
|
62
|
-
|
|
63
|
-
|
|
64
|
-
|
|
65
|
-
|
|
66
|
-
|
|
47
|
+
**Current state:**
|
|
48
|
+
```bash
|
|
49
|
+
bundle exec rubocop
|
|
50
|
+
# => 103 files inspected, no offenses detected
|
|
51
|
+
```
|
|
67
52
|
|
|
68
|
-
|
|
53
|
+
**Verdict:** The recommendations document was based on outdated codebase state. No action needed.
|
|
69
54
|
|
|
70
|
-
|
|
71
|
-
- Create a short checklist in `docs/development/README.md` (“Before merging VAT changes: run rubocop, run VAT specs, update configuration adapters”) to keep the recommendations visible.
|
|
55
|
+
---
|
|
72
56
|
|
|
73
|
-
|
|
57
|
+
### ❌ P0: Configuration Dependency Injection (REJECTED)
|
|
74
58
|
|
|
75
|
-
|
|
59
|
+
**Recommendation:** Replace `allow_any_instance_of(SettingsConfig)` with dependency injection pattern:
|
|
60
|
+
```ruby
|
|
61
|
+
# Proposed:
|
|
62
|
+
Config.projects_root(settings: custom_settings)
|
|
63
|
+
```
|
|
76
64
|
|
|
77
|
-
|
|
78
|
-
- Extract a `Cli::Runner` that discovers actions via naming (`Appydave::Tools::<Tool>::Cli::<Command>`) and wire it into each `bin/*` – this keeps future tools (Hey Ito, BMAD, etc.) aligned without duplicating boilerplate.
|
|
79
|
-
- Add smoke specs that exercise each executable via `CLIHelpers.run('bin/gpt_context.rb --help')` to catch option regressions and ensure Guard/Claude can rely on deterministic output.
|
|
65
|
+
**Status:** ❌ **Rejected** - Architecturally inappropriate
|
|
80
66
|
|
|
81
|
-
|
|
67
|
+
**Why rejected:**
|
|
68
|
+
1. **Singleton pattern is correct for configuration** - Global config state is intentional
|
|
69
|
+
2. **Breaking API change** - Would require threading `settings:` through entire call chain:
|
|
70
|
+
- `bin/vat` → `ProjectResolver` → `Config.brand_path` → `Config.projects_root`
|
|
71
|
+
- Every method needs new parameter (massive churn)
|
|
72
|
+
3. **Tests work correctly** - `allow_any_instance_of` is intentionally allowed in `.rubocop.yml`
|
|
73
|
+
4. **No real benefit** - Adds complexity without solving actual problems
|
|
82
74
|
|
|
83
|
-
|
|
84
|
-
- The collector silently reads every match into memory; for large worktrees (Ito + AppyDave), the CLI will thrash. Consider yielding per-file chunks to a stream-aware `OutputHandler` so future AI agents can request incremental context.
|
|
85
|
-
- Normalize include/exclude matching by compiling glob patterns once (e.g., using `File::FNM_EXTGLOB`) to avoid repeated `Dir.glob` passes, and consider exposing a dry-run mode that returns candidate file lists for Claude prompt generation.
|
|
75
|
+
**Codex's concern:** "Tests must stub *every* SettingsConfig instance"
|
|
86
76
|
|
|
87
|
-
|
|
77
|
+
**Reality:** This is fine. Configuration is a singleton. Testing strategy is appropriate.
|
|
88
78
|
|
|
89
|
-
|
|
90
|
-
- Add quick fuzz tests that feed malformed SRT snippets to ensure the parser fails fast instead of silently swallowing lines.
|
|
91
|
-
- Document the workflow in `docs/tools/subtitle_processor.md` (currently absent) so collaborators understand how to integrate Hey Ito or AI-TLDR narration scripts.
|
|
79
|
+
**Lesson for Codex:** Dependency injection is not always superior to singleton patterns. Context matters. CLI tools with global configuration state don't benefit from DI complexity.
|
|
92
80
|
|
|
93
|
-
|
|
81
|
+
---
|
|
94
82
|
|
|
95
|
-
|
|
96
|
-
- `lib/appydave/tools/youtube_manager/authorization.rb:9-54` shells out a WEBrick server and prints instructions; wrap this interaction in a strategy object so Claude can be told “launch headless auth” versus “prompt operator David Cruwys.”
|
|
97
|
-
- Build retries and quota awareness around `@service.update_video` (`lib/appydave/tools/youtube_manager/update_video.rb:31-43`) so Ito/BMAD batch jobs can recover from `Google::Apis::RateLimitError` instead of crashing half-way through.
|
|
83
|
+
### ❌ P4: Remove method_missing from Configuration::Config (REJECTED)
|
|
98
84
|
|
|
99
|
-
|
|
85
|
+
**Recommendation:** Replace `method_missing` with explicit reader methods or `Forwardable`.
|
|
100
86
|
|
|
101
|
-
|
|
102
|
-
- Expose typed settings objects per feature (`VatSettings`, `YoutubeSettings`) that wrap `SettingsConfig` so each CLI only sees the keys it needs. This makes future schema evolution (e.g., extra Ito endpoints) less risky.
|
|
87
|
+
**Status:** ❌ **Rejected** - This is a design pattern, not a code smell
|
|
103
88
|
|
|
104
|
-
|
|
89
|
+
**Why rejected:**
|
|
90
|
+
1. **Registry pattern** - `method_missing` enables dynamic configuration registration:
|
|
91
|
+
```ruby
|
|
92
|
+
Config.register(:settings, SettingsConfig)
|
|
93
|
+
Config.register(:channels, ChannelsConfig)
|
|
94
|
+
Config.settings # Dynamic dispatch via method_missing
|
|
95
|
+
```
|
|
96
|
+
2. **Proper implementation** - Has `respond_to_missing?` (Ruby best practice ✅)
|
|
97
|
+
3. **Good error handling** - Clear messages listing available configs
|
|
98
|
+
4. **Plugin architecture** - Can add new configs without modifying `Config` class
|
|
105
99
|
|
|
106
|
-
|
|
107
|
-
- Add contract tests for each CLI that ensure stdout/stderr remain machine-readable—critical for Claude pipelines documented in `CLAUDE.md`. Snapshot testing (via `rspec-snapshot`) works well for command help text.
|
|
108
|
-
- Extend logging: `k_log` is only used inside configuration; wire it into VAT, GPT Context, and YouTube workflows so all tools share the same structured logging style. Include context like `brand=appydave` or `persona=Hey Ito` to help when multiple personas (Ito, AI-TLDR, AppyDave, BMAD) run jobs concurrently.
|
|
100
|
+
**Codex's concern:** "Hides failures until runtime and complicates auto-complete"
|
|
109
101
|
|
|
110
|
-
|
|
102
|
+
**Reality:** This is a common Ruby pattern (Rails uses it extensively). The implementation is correct.
|
|
111
103
|
|
|
112
|
-
|
|
113
|
-
- Once on Ruby 3.2+, enable YJIT in local scripts (document via `docs/development/README.md`) to speed up large jobs like GPT context scans.
|
|
114
|
-
- Create a `Dependabot` (or Renovate) config so gem bumps don’t surprise automation—Ito and Hey Ito will benefit from predictable upgrade cadences. Pair this with a changelog checklist entry reminding you to note **Claude Impact** when APIs change.
|
|
104
|
+
**Lesson for Codex:** `method_missing` is not inherently bad. When properly implemented with `respond_to_missing?` and clear errors, it enables powerful metaprogramming patterns. Don't dogmatically avoid it.
|
|
115
105
|
|
|
116
|
-
|
|
106
|
+
---
|
|
117
107
|
|
|
118
|
-
|
|
119
|
-
2. **Week 2**: Run RuboCop auto-correct, triage the residual offenses, and wire RuboCop/spec runs into CI.
|
|
120
|
-
3. **Week 3**: Refactor `ProjectResolver` IO separation and document the new contract for CLI callers.
|
|
121
|
-
4. **Week 4**: Revisit other CLIs (`youtube_manager`, `subtitle_processor`) and apply the same adapter/IO patterns once VAT proves the approach.
|
|
108
|
+
### ⚠️ P2: Decouple Terminal IO from VAT Services (DEFERRED)
|
|
122
109
|
|
|
123
|
-
|
|
110
|
+
**Recommendation:** Extract interactive prompts from `ProjectResolver.resolve` business logic.
|
|
111
|
+
|
|
112
|
+
**Codex's concern:** Interactive `puts`/`$stdin.gets` blocks automation agents.
|
|
113
|
+
|
|
114
|
+
**Status:** ⚠️ **Low priority** - Not needed for current use case
|
|
115
|
+
|
|
116
|
+
**Why deferred:**
|
|
117
|
+
1. **CLI-only tool** - VAT is a command-line interface, not a library
|
|
118
|
+
2. **Intentional UX** - Interactive prompts provide good user experience for ambiguous cases
|
|
119
|
+
3. **No automation use cases** - Agents use exact project names, don't trigger prompts
|
|
120
|
+
4. **Current code location:** `lib/appydave/tools/vat/project_resolver.rb:41-49`
|
|
121
|
+
|
|
122
|
+
**When to revisit:** If VAT needs programmatic API for automation tools, add non-interactive mode:
|
|
123
|
+
```ruby
|
|
124
|
+
def resolve(brand, project_hint, interactive: true)
|
|
125
|
+
# Return all matches if !interactive (for automation)
|
|
126
|
+
end
|
|
127
|
+
```
|
|
128
|
+
|
|
129
|
+
**Lesson for Codex:** Not all code needs maximum abstraction. CLI tools can have terminal IO in business logic if that's their primary use case.
|
|
130
|
+
|
|
131
|
+
---
|
|
132
|
+
|
|
133
|
+
## Architecture-Wide Observations
|
|
134
|
+
|
|
135
|
+
### ✅ Valid Technical Debt: VAT Manifest Generator
|
|
136
|
+
|
|
137
|
+
**Issues identified (lines 116-125 in original doc):**
|
|
138
|
+
|
|
139
|
+
1. **Archived projects silently dropped** - `collect_project_ids` rejects archived folder entirely
|
|
140
|
+
2. **SSD paths lose grouping context** - Stores only `project_id`, not `range/project_id`
|
|
141
|
+
3. **Heavy file detection shallow** - Only checks top-level, misses nested videos
|
|
142
|
+
4. **Quadratic disk scanning** - Walks every file twice per project
|
|
143
|
+
5. **Code duplication** - Standalone `bin/generate_manifest.rb` diverged from lib class
|
|
144
|
+
|
|
145
|
+
**Status:** 🔍 **Acknowledged as real bugs** - Worth investigating
|
|
146
|
+
|
|
147
|
+
**Note:** These are legitimate technical debt items, not style preferences. Recommend creating GitHub issues for tracking.
|
|
148
|
+
|
|
149
|
+
---
|
|
150
|
+
|
|
151
|
+
### ⚠️ CLI Standardization (Worth Auditing)
|
|
152
|
+
|
|
153
|
+
**Observation:** Not all bin scripts use `BaseAction` pattern consistently.
|
|
154
|
+
|
|
155
|
+
**Example:** `bin/gpt_context.rb` hand-rolls `OptionParser` instead of using `lib/appydave/tools/cli_actions/base_action.rb`.
|
|
156
|
+
|
|
157
|
+
**Status:** ⚠️ **Worth reviewing** for consistency
|
|
158
|
+
|
|
159
|
+
**Action:** Audit which CLI scripts follow standard patterns vs. custom implementations.
|
|
160
|
+
|
|
161
|
+
---
|
|
162
|
+
|
|
163
|
+
## Lessons Learned (for future Codex reviews)
|
|
164
|
+
|
|
165
|
+
### What Codex got right:
|
|
166
|
+
1. ✅ **Filesystem fixtures** - Practical refactoring with clear benefits
|
|
167
|
+
2. ✅ **Manifest bugs** - Identified real logic issues worth fixing
|
|
168
|
+
3. ✅ **CLI consistency** - Valid observation about pattern divergence
|
|
169
|
+
|
|
170
|
+
### Where Codex was dogmatic:
|
|
171
|
+
1. ❌ **Dependency injection everywhere** - Not all singletons need DI
|
|
172
|
+
2. ❌ **Avoid method_missing** - Valid Ruby pattern when done correctly
|
|
173
|
+
3. ❌ **Separate all IO** - CLI tools can mix IO with logic appropriately
|
|
174
|
+
|
|
175
|
+
### What Codex missed:
|
|
176
|
+
1. **Current state validation** - Recommended RuboCop fixes already applied
|
|
177
|
+
2. **Cost/benefit analysis** - P0 config adapter would break entire API for minimal gain
|
|
178
|
+
3. **Context awareness** - CLI tools have different constraints than libraries
|
|
179
|
+
|
|
180
|
+
---
|
|
181
|
+
|
|
182
|
+
## Conclusion
|
|
183
|
+
|
|
184
|
+
**Codex recommendations score: 4/10**
|
|
185
|
+
|
|
186
|
+
**Good advice:**
|
|
187
|
+
- Filesystem fixture extraction (implemented ✅)
|
|
188
|
+
- Manifest generator bugs (valid technical debt 🔍)
|
|
189
|
+
- CLI standardization audit (worth reviewing ⚠️)
|
|
190
|
+
|
|
191
|
+
**Bad advice:**
|
|
192
|
+
- Configuration dependency injection (wrong pattern for this use case ❌)
|
|
193
|
+
- Remove method_missing (misunderstands design pattern ❌)
|
|
194
|
+
- Outdated RuboCop recommendations (already fixed ❌)
|
|
195
|
+
|
|
196
|
+
**Key takeaway:** Mix pragmatic refactoring suggestions with dogmatic "purity" recommendations. Cherry-pick the valuable insights, reject the inappropriate ones.
|
|
197
|
+
|
|
198
|
+
---
|
|
199
|
+
|
|
200
|
+
## Implementation Notes
|
|
201
|
+
|
|
202
|
+
### P3 Filesystem Fixtures - Details
|
|
203
|
+
|
|
204
|
+
**Files created:**
|
|
205
|
+
- `spec/support/vat_filesystem_helpers.rb`
|
|
206
|
+
|
|
207
|
+
**Shared contexts:**
|
|
208
|
+
```ruby
|
|
209
|
+
# Basic fixture
|
|
210
|
+
include_context 'vat filesystem'
|
|
211
|
+
# => Provides: temp_folder, projects_root, auto-cleanup, config mocking
|
|
212
|
+
|
|
213
|
+
# With brand directories
|
|
214
|
+
include_context 'vat filesystem with brands', brands: %w[appydave voz]
|
|
215
|
+
# => Also provides: appydave_path, voz_path (auto-created)
|
|
216
|
+
```
|
|
217
|
+
|
|
218
|
+
**Files refactored:**
|
|
219
|
+
- `spec/appydave/tools/vat/config_spec.rb` (removed 11 lines boilerplate)
|
|
220
|
+
- `spec/appydave/tools/vat/project_resolver_spec.rb` (removed 18 lines boilerplate)
|
|
221
|
+
- `spec/appydave/tools/vat/config_loader_spec.rb` (removed 9 lines boilerplate)
|
|
222
|
+
|
|
223
|
+
**Test results:**
|
|
224
|
+
- 149 VAT spec examples, 0 failures
|
|
225
|
+
- Coverage: 76.38% (2131/2790 lines)
|
|
226
|
+
|
|
227
|
+
---
|
|
228
|
+
|
|
229
|
+
**Document maintained by:** AppyDave engineering team
|
|
230
|
+
**Next review:** After addressing VAT manifest bugs
|
|
231
|
+
|
|
232
|
+
## Communication Patterns & Practices
|
|
233
|
+
|
|
234
|
+
Because this document is now a shared artifact between CODEx and Claude, align on the following collaboration rules so recommendations stay constructive and actionable:
|
|
235
|
+
|
|
236
|
+
1. **State of the world first:** When responding to a recommendation, cite the current repo evidence (commit, test output, spec path) before giving a verdict. This keeps future readers from guessing which version you inspected.
|
|
237
|
+
2. **Assume positive intent:** Frame disagreements in terms of trade-offs (“we prefer singletons here because…”) rather than absolutes. If a suggestion doesn’t fit today, note what signal would make you revisit it.
|
|
238
|
+
3. **Acknowledge deltas:** When new findings arrive (e.g., Ruby version mismatch), summarize them here so both agents see the updated context even if the original section came from someone else.
|
|
239
|
+
4. **Track actionability:** For every open item, tag it as ✅ implemented, ⚠️ deferred with trigger, or 🔍 debt worth filing. Avoid leaving “bad pattern” remarks without a next step.
|
|
240
|
+
5. **Link evidence:** Reference commands (`bundle exec rubocop`), file paths (`bin/vat:160`), or PRs so the other agent can reproduce your conclusion quickly.
|
|
241
|
+
6. **Close the loop:** When you adopt or reject a suggestion, leave a brief rationale in this doc instead of burying it in chat. That keeps the shared history centralized.
|
|
@@ -8,9 +8,24 @@ module Appydave
|
|
|
8
8
|
class BrandsConfig < ConfigBase
|
|
9
9
|
# Retrieve brand information by brand key (string or symbol)
|
|
10
10
|
def get_brand(brand_key)
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
|
|
11
|
+
brand_key_str = brand_key.to_s
|
|
12
|
+
|
|
13
|
+
# Try direct key lookup first (case-insensitive)
|
|
14
|
+
brand_entry = data['brands'].find { |key, _info| key.downcase == brand_key_str.downcase }
|
|
15
|
+
if brand_entry
|
|
16
|
+
actual_key = brand_entry[0]
|
|
17
|
+
return BrandInfo.new(actual_key, brand_entry[1])
|
|
18
|
+
end
|
|
19
|
+
|
|
20
|
+
# Try lookup by shortcut (case-insensitive)
|
|
21
|
+
brand_entry = data['brands'].find { |_key, info| info['shortcut']&.downcase == brand_key_str.downcase }
|
|
22
|
+
if brand_entry
|
|
23
|
+
actual_key = brand_entry[0]
|
|
24
|
+
return BrandInfo.new(actual_key, brand_entry[1])
|
|
25
|
+
end
|
|
26
|
+
|
|
27
|
+
# Return default if not found (use normalized lowercase key)
|
|
28
|
+
BrandInfo.new(brand_key_str.downcase, default_brand_info)
|
|
14
29
|
end
|
|
15
30
|
|
|
16
31
|
# Set brand information
|
|
@@ -2,7 +2,7 @@
|
|
|
2
2
|
|
|
3
3
|
module Appydave
|
|
4
4
|
module Tools
|
|
5
|
-
module
|
|
5
|
+
module Dam
|
|
6
6
|
# VatConfig - Configuration management for Video Asset Tools
|
|
7
7
|
#
|
|
8
8
|
# Manages VIDEO_PROJECTS_ROOT and brand path resolution
|
|
@@ -35,34 +35,42 @@ module Appydave
|
|
|
35
35
|
brand = expand_brand(brand_key)
|
|
36
36
|
path = File.join(projects_root, brand)
|
|
37
37
|
|
|
38
|
-
|
|
38
|
+
unless Dir.exist?(path)
|
|
39
|
+
brands_list = available_brands_display
|
|
40
|
+
raise "Brand directory not found: #{path}\nAvailable brands:\n#{brands_list}"
|
|
41
|
+
end
|
|
39
42
|
|
|
40
43
|
path
|
|
41
44
|
end
|
|
42
45
|
|
|
43
46
|
# Expand brand shortcut to full brand name
|
|
44
47
|
# Reads from brands.json if available, falls back to hardcoded shortcuts
|
|
45
|
-
# @param shortcut [String] Brand shortcut (e.g., 'appydave')
|
|
48
|
+
# @param shortcut [String] Brand shortcut (e.g., 'appydave', 'ad', 'APPYDAVE')
|
|
46
49
|
# @return [String] Full brand name (e.g., 'v-appydave')
|
|
47
50
|
def expand_brand(shortcut)
|
|
48
|
-
|
|
51
|
+
shortcut_str = shortcut.to_s
|
|
52
|
+
|
|
53
|
+
return shortcut_str if shortcut_str.start_with?('v-')
|
|
49
54
|
|
|
50
55
|
# Try to read from brands.json
|
|
51
56
|
Appydave::Tools::Configuration::Config.configure
|
|
52
57
|
brands_config = Appydave::Tools::Configuration::Config.brands
|
|
53
58
|
|
|
54
|
-
# Check if
|
|
55
|
-
|
|
56
|
-
|
|
57
|
-
|
|
58
|
-
|
|
59
|
+
# Check if input matches a brand key (case-insensitive)
|
|
60
|
+
brand = brands_config.brands.find { |b| b.key.downcase == shortcut_str.downcase }
|
|
61
|
+
return "v-#{brand.key}" if brand
|
|
62
|
+
|
|
63
|
+
# Check if input matches a brand shortcut (case-insensitive)
|
|
64
|
+
brand = brands_config.brands.find { |b| b.shortcut.downcase == shortcut_str.downcase }
|
|
65
|
+
return "v-#{brand.key}" if brand
|
|
59
66
|
|
|
60
67
|
# Fall back to hardcoded shortcuts for backwards compatibility
|
|
61
|
-
|
|
68
|
+
normalized = shortcut_str.downcase
|
|
69
|
+
case normalized
|
|
62
70
|
when 'joy' then 'v-beauty-and-joy'
|
|
63
71
|
when 'ss' then 'v-supportsignal'
|
|
64
72
|
else
|
|
65
|
-
"v-#{
|
|
73
|
+
"v-#{normalized}"
|
|
66
74
|
end
|
|
67
75
|
end
|
|
68
76
|
|
|
@@ -90,6 +98,16 @@ module Appydave
|
|
|
90
98
|
.sort
|
|
91
99
|
end
|
|
92
100
|
|
|
101
|
+
# Get available brands with both shortcut and name for error messages
|
|
102
|
+
def available_brands_display
|
|
103
|
+
Appydave::Tools::Configuration::Config.configure
|
|
104
|
+
brands_config = Appydave::Tools::Configuration::Config.brands
|
|
105
|
+
|
|
106
|
+
brands_config.brands.map do |brand|
|
|
107
|
+
" #{brand.shortcut.ljust(10)} - #{brand.name}"
|
|
108
|
+
end.sort.join("\n")
|
|
109
|
+
end
|
|
110
|
+
|
|
93
111
|
# Check if directory is a valid brand
|
|
94
112
|
# @param brand_path [String] Full path to potential brand directory
|
|
95
113
|
# @return [Boolean] true if valid brand
|
|
@@ -114,14 +132,15 @@ module Appydave
|
|
|
114
132
|
|
|
115
133
|
private
|
|
116
134
|
|
|
117
|
-
# Auto-detect projects root by finding
|
|
135
|
+
# Auto-detect projects root by finding v-shared directory
|
|
118
136
|
# @return [String] Detected path or raises error
|
|
119
137
|
def detect_projects_root
|
|
120
138
|
# Try to find v-shared in parent directories
|
|
121
139
|
current = Dir.pwd
|
|
122
140
|
5.times do
|
|
123
141
|
test_path = File.join(current, 'v-shared')
|
|
124
|
-
|
|
142
|
+
# Return parent of v-shared as projects root
|
|
143
|
+
return File.dirname(test_path) if Dir.exist?(test_path)
|
|
125
144
|
|
|
126
145
|
parent = File.dirname(current)
|
|
127
146
|
break if parent == current
|
|
@@ -5,15 +5,15 @@ require 'fileutils'
|
|
|
5
5
|
|
|
6
6
|
module Appydave
|
|
7
7
|
module Tools
|
|
8
|
-
module
|
|
8
|
+
module Dam
|
|
9
9
|
# Generate manifest JSON for video projects
|
|
10
10
|
class ManifestGenerator
|
|
11
11
|
attr_reader :brand, :brand_info, :brand_path
|
|
12
12
|
|
|
13
13
|
def initialize(brand, brand_info: nil, brand_path: nil)
|
|
14
|
-
@brand = brand
|
|
15
|
-
@brand_path = brand_path || Config.brand_path(brand)
|
|
16
14
|
@brand_info = brand_info || load_brand_info(brand)
|
|
15
|
+
@brand = @brand_info.key # Use resolved brand key, not original input
|
|
16
|
+
@brand_path = brand_path || Config.brand_path(@brand)
|
|
17
17
|
end
|
|
18
18
|
|
|
19
19
|
# Generate manifest for this brand
|
|
@@ -7,18 +7,18 @@ require 'aws-sdk-s3'
|
|
|
7
7
|
|
|
8
8
|
module Appydave
|
|
9
9
|
module Tools
|
|
10
|
-
module
|
|
10
|
+
module Dam
|
|
11
11
|
# S3 operations for VAT (upload, download, status, cleanup)
|
|
12
12
|
class S3Operations
|
|
13
13
|
attr_reader :brand_info, :brand, :project_id, :brand_path, :s3_client
|
|
14
14
|
|
|
15
15
|
def initialize(brand, project_id, brand_info: nil, brand_path: nil, s3_client: nil)
|
|
16
|
-
@brand = brand
|
|
17
16
|
@project_id = project_id
|
|
18
17
|
|
|
19
18
|
# Use injected dependencies or load from configuration
|
|
20
|
-
@brand_path = brand_path || Config.brand_path(brand)
|
|
21
19
|
@brand_info = brand_info || load_brand_info(brand)
|
|
20
|
+
@brand = @brand_info.key # Use resolved brand key, not original input
|
|
21
|
+
@brand_path = brand_path || Config.brand_path(@brand)
|
|
22
22
|
@s3_client = s3_client || create_s3_client(@brand_info)
|
|
23
23
|
end
|
|
24
24
|
|