source_monitor 0.3.1 → 0.3.3
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/.claude/agent-memory/vbw-vbw-dev/MEMORY.md +34 -0
- data/.claude/agent-memory/vbw-vbw-lead/MEMORY.md +49 -0
- data/.claude/commands/release.md +212 -0
- data/.claude/skills/sm-host-setup/SKILL.md +7 -3
- data/.claude/skills/sm-host-setup/reference/setup-checklist.md +3 -0
- data/.claude/skills/sm-job/SKILL.md +10 -9
- data/.gitignore +4 -0
- data/AGENTS.md +20 -57
- data/CHANGELOG.md +22 -0
- data/CLAUDE.md +1 -1
- data/CONTRIBUTING.md +5 -5
- data/Gemfile.lock +1 -1
- data/README.md +18 -5
- data/VERSION +1 -0
- data/docs/deployment.md +1 -1
- data/docs/setup.md +8 -8
- data/lib/generators/source_monitor/install/install_generator.rb +100 -0
- data/lib/source_monitor/setup/skills_installer.rb +94 -0
- data/lib/source_monitor/version.rb +1 -1
- metadata +6 -3
- data/.vbw-planning/.notification-log.jsonl +0 -246
- data/.vbw-planning/.session-log.jsonl +0 -992
data/README.md
CHANGED
|
@@ -9,8 +9,8 @@ SourceMonitor is a production-ready Rails 8 mountable engine for ingesting, norm
|
|
|
9
9
|
In your host Rails app:
|
|
10
10
|
|
|
11
11
|
```bash
|
|
12
|
-
bundle add source_monitor --version "~> 0.1
|
|
13
|
-
# or add `gem "source_monitor", "~> 0.1
|
|
12
|
+
bundle add source_monitor --version "~> 0.3.1"
|
|
13
|
+
# or add `gem "source_monitor", "~> 0.3.1"` manually, then run:
|
|
14
14
|
bundle install
|
|
15
15
|
```
|
|
16
16
|
|
|
@@ -25,7 +25,7 @@ This exposes `bin/source_monitor` (via Bundler binstubs) so you can run the guid
|
|
|
25
25
|
- First-class observability through ActiveSupport notifications and `SourceMonitor::Metrics` counters/gauges
|
|
26
26
|
|
|
27
27
|
## Requirements
|
|
28
|
-
- Ruby
|
|
28
|
+
- Ruby 4.0+ (we recommend [rbenv](https://github.com/rbenv/rbenv) for local development, but use whatever Ruby version manager suits your environment—asdf, chruby, rvm, or container-based workflows all work fine)
|
|
29
29
|
- Rails ≥ 8.0.2.1 in the host application
|
|
30
30
|
- PostgreSQL 13+ (engine migrations use JSONB, SKIP LOCKED, advisory locks, and Solid Cable tables)
|
|
31
31
|
- Node.js 18+ (npm or Yarn) for asset linting and the Tailwind/esbuild bundling pipeline
|
|
@@ -41,7 +41,7 @@ This exposes `bin/source_monitor` (via Bundler binstubs) so you can run the guid
|
|
|
41
41
|
Before running any SourceMonitor commands inside your host app, add the gem and install dependencies:
|
|
42
42
|
|
|
43
43
|
```bash
|
|
44
|
-
bundle add source_monitor --version "~> 0.1
|
|
44
|
+
bundle add source_monitor --version "~> 0.3.1"
|
|
45
45
|
# or edit your Gemfile, then run
|
|
46
46
|
bundle install
|
|
47
47
|
```
|
|
@@ -111,6 +111,19 @@ The generated initializer documents every setting. Key areas:
|
|
|
111
111
|
|
|
112
112
|
See [docs/configuration.md](docs/configuration.md) for exhaustive coverage and examples.
|
|
113
113
|
|
|
114
|
+
## Claude Code Skills
|
|
115
|
+
|
|
116
|
+
SourceMonitor ships 14 engine-specific Claude Code skills (`sm-*` prefix) that give AI agents deep context about the engine's domain model, configuration DSL, pipeline stages, and testing conventions. Skills are bundled with the gem and installed into your host app's `.claude/skills/` directory.
|
|
117
|
+
|
|
118
|
+
```bash
|
|
119
|
+
bin/rails source_monitor:skills:install # Consumer skills (host app integration)
|
|
120
|
+
bin/rails source_monitor:skills:contributor # Contributor skills (engine development)
|
|
121
|
+
bin/rails source_monitor:skills:all # All skills
|
|
122
|
+
bin/rails source_monitor:skills:remove # Remove all sm-* skills
|
|
123
|
+
```
|
|
124
|
+
|
|
125
|
+
The guided installer (`bin/source_monitor install`) also offers to install consumer skills as part of the setup workflow.
|
|
126
|
+
|
|
114
127
|
## Deployment Considerations
|
|
115
128
|
- Copy engine migrations before every deploy and run `bin/rails db:migrate`.
|
|
116
129
|
- Precompile assets so SourceMonitor's bundled CSS/JS outputs are available at runtime.
|
|
@@ -130,7 +143,7 @@ Common installation and runtime issues (missing migrations, realtime not streami
|
|
|
130
143
|
- Quality checks: `bin/rubocop`, `bin/brakeman --no-pager`, `bin/lint-assets`.
|
|
131
144
|
- Record HTTP fixtures with VCR under `test/vcr_cassettes/` and keep coverage ≥ 90% for new code.
|
|
132
145
|
|
|
133
|
-
Contributions follow the clean architecture and TDD guidelines in
|
|
146
|
+
Contributions follow the clean architecture and TDD guidelines in `CLAUDE.md` and `AGENTS.md`.
|
|
134
147
|
|
|
135
148
|
## License
|
|
136
149
|
SourceMonitor is released under the [MIT License](MIT-LICENSE).
|
data/VERSION
ADDED
|
@@ -0,0 +1 @@
|
|
|
1
|
+
0.3.3
|
data/docs/deployment.md
CHANGED
|
@@ -60,7 +60,7 @@ Keep this guide alongside your platform runbooks so teams can confidently deploy
|
|
|
60
60
|
|
|
61
61
|
## Container Reference Stack
|
|
62
62
|
|
|
63
|
-
The repository ships a reusable Docker stack under `examples/docker` that mirrors the recommended process model. It builds a Ruby
|
|
63
|
+
The repository ships a reusable Docker stack under `examples/docker` that mirrors the recommended process model. It builds a Ruby 4.0 image with Node, mounts your generated example via `APP_PATH`, and launches three services (`web`, `worker`, `scheduler`) alongside Postgres and Redis. Use it to trial production settings locally or as a baseline for ECS/Kubernetes manifests.
|
|
64
64
|
|
|
65
65
|
## Setup Workflow Rollout Checklist
|
|
66
66
|
|
data/docs/setup.md
CHANGED
|
@@ -6,8 +6,8 @@ This guide consolidates the new guided installer, verification commands, and rol
|
|
|
6
6
|
|
|
7
7
|
| Requirement | Minimum | Notes |
|
|
8
8
|
| --- | --- | --- |
|
|
9
|
-
| Ruby |
|
|
10
|
-
| Rails | 8.
|
|
9
|
+
| Ruby | 4.0.1 | Use rbenv and match the engine's `.ruby-version`. |
|
|
10
|
+
| Rails | 8.1.2 | Run `bin/rails about` inside the host to confirm. |
|
|
11
11
|
| PostgreSQL | 14+ | Required for Solid Queue tables and item storage. |
|
|
12
12
|
| Node.js | 18+ | Needed for Tailwind/esbuild assets when the host owns node tooling. |
|
|
13
13
|
| Background jobs | Solid Queue (>= 0.3, < 3.0) | Add `solid_queue` to the host Gemfile if not present. |
|
|
@@ -18,8 +18,8 @@ This guide consolidates the new guided installer, verification commands, and rol
|
|
|
18
18
|
Run these commands inside your host Rails application before invoking the guided workflow:
|
|
19
19
|
|
|
20
20
|
```bash
|
|
21
|
-
bundle add source_monitor --version "~> 0.1
|
|
22
|
-
# or add gem "source_monitor", "~> 0.1
|
|
21
|
+
bundle add source_monitor --version "~> 0.3.1"
|
|
22
|
+
# or add gem "source_monitor", "~> 0.3.1" to Gemfile manually
|
|
23
23
|
bundle install
|
|
24
24
|
```
|
|
25
25
|
|
|
@@ -48,8 +48,8 @@ This ensures Bundler can load SourceMonitor so the commands below are available.
|
|
|
48
48
|
3. **Start background workers:**
|
|
49
49
|
```bash
|
|
50
50
|
bin/rails solid_queue:start
|
|
51
|
-
bin/jobs --recurring_schedule_file=config/recurring.yml # optional recurring scheduler
|
|
52
51
|
```
|
|
52
|
+
Recurring jobs (fetch scheduling, scraping, cleanup) are automatically configured in `config/recurring.yml` by the install generator. They'll run automatically with `bin/dev` or `bin/jobs`.
|
|
53
53
|
|
|
54
54
|
4. **Visit the dashboard** at the chosen mount path, create a source, and trigger “Fetch Now” to validate realtime updates and Solid Queue processing.
|
|
55
55
|
|
|
@@ -83,7 +83,7 @@ Prefer to script each step or plug SourceMonitor into an existing deployment che
|
|
|
83
83
|
| --- | --- | --- |
|
|
84
84
|
| 1 | `gem "source_monitor", github: "dchuk/source_monitor"` | Add the engine to your Gemfile (skip if already present) |
|
|
85
85
|
| 2 | `bundle install` | Install Ruby dependencies |
|
|
86
|
-
| 3 | `bin/rails generate source_monitor:install --mount-path=/source_monitor` | Mount the engine
|
|
86
|
+
| 3 | `bin/rails generate source_monitor:install --mount-path=/source_monitor` | Mount the engine, create the initializer, and configure recurring jobs |
|
|
87
87
|
| 4 | `bin/rails railties:install:migrations FROM=source_monitor` | Copy engine migrations (idempotent) |
|
|
88
88
|
| 5 | `bin/rails db:migrate` | Apply schema updates, including Solid Queue tables |
|
|
89
89
|
| 6 | `bin/rails solid_queue:start` | Ensure jobs process via Solid Queue |
|
|
@@ -95,11 +95,11 @@ Prefer to script each step or plug SourceMonitor into an existing deployment che
|
|
|
95
95
|
### Step-by-step Details
|
|
96
96
|
|
|
97
97
|
1. **Add the gem** to the host `Gemfile` (GitHub edge or released version) and run `bundle install`. If your host manages node tooling, run `npm install` also.
|
|
98
|
-
2. **Install the engine** via `bin/rails generate source_monitor:install --mount-path=/source_monitor`. The generator mounts the engine, creates `config/initializers/source_monitor.rb`, and
|
|
98
|
+
2. **Install the engine** via `bin/rails generate source_monitor:install --mount-path=/source_monitor`. The generator mounts the engine, creates `config/initializers/source_monitor.rb`, and configures recurring Solid Queue jobs in `config/recurring.yml`. Re-running the generator is safe; it detects existing mounts/initializers and skips entries that are already present.
|
|
99
99
|
3. **Copy migrations** with `bin/rails railties:install:migrations FROM=source_monitor`. This brings in the SourceMonitor tables plus Solid Cable/Queue schema when needed. The command is idempotent—run it again after upgrading the gem.
|
|
100
100
|
4. **Apply database changes** using `bin/rails db:migrate`. If your host already installed Solid Queue migrations manually, delete duplicate files before migrating.
|
|
101
101
|
5. **Wire Action Cable** if necessary. SourceMonitor defaults to Solid Cable; confirm `ApplicationCable::Connection`/`Channel` exist and that `config/initializers/source_monitor.rb` uses the adapter you expect. To switch to Redis, set `config.realtime.adapter = :redis` and `config.realtime.redis_url`.
|
|
102
|
-
6. **Start workers** with `bin/rails solid_queue:start` (or your process manager).
|
|
102
|
+
6. **Start workers** with `bin/rails solid_queue:start` (or your process manager). The install generator automatically configures recurring jobs in `config/recurring.yml` for fetch scheduling, scraping, and cleanup. They'll run with `bin/dev` or `bin/jobs`.
|
|
103
103
|
7. **Review the initializer** and tune queue names, HTTP timeouts, scraping adapters, retention limits, authentication hooks, and Mission Control integration. The [configuration reference](configuration.md) details every option.
|
|
104
104
|
8. **Verify the install**: run `bin/source_monitor verify` to ensure Solid Queue workers and Action Cable are healthy, then visit the mount path to trigger a fetch manually. Enable telemetry if you want JSON logs recorded for support.
|
|
105
105
|
|
|
@@ -1,5 +1,6 @@
|
|
|
1
1
|
# frozen_string_literal: true
|
|
2
2
|
|
|
3
|
+
require "yaml"
|
|
3
4
|
require "rails/generators"
|
|
4
5
|
require "rails/generators/base"
|
|
5
6
|
|
|
@@ -32,7 +33,26 @@ module SourceMonitor
|
|
|
32
33
|
template "source_monitor.rb.tt", initializer_path
|
|
33
34
|
end
|
|
34
35
|
|
|
36
|
+
def configure_recurring_jobs
|
|
37
|
+
recurring_path = "config/recurring.yml"
|
|
38
|
+
destination = File.join(destination_root, recurring_path)
|
|
39
|
+
|
|
40
|
+
if recurring_file_has_source_monitor_entries?(destination)
|
|
41
|
+
say_status :skip, "#{recurring_path} (SourceMonitor entries already present)", :yellow
|
|
42
|
+
return
|
|
43
|
+
end
|
|
44
|
+
|
|
45
|
+
if File.exist?(destination)
|
|
46
|
+
merge_into_existing_recurring(destination, recurring_path)
|
|
47
|
+
else
|
|
48
|
+
create_recurring_file(destination, recurring_path)
|
|
49
|
+
end
|
|
50
|
+
end
|
|
51
|
+
|
|
35
52
|
def print_next_steps
|
|
53
|
+
say_status :info,
|
|
54
|
+
"Recurring jobs configured in config/recurring.yml — they'll run automatically with bin/dev or bin/jobs.",
|
|
55
|
+
:green
|
|
36
56
|
say_status :info,
|
|
37
57
|
"Next steps: review docs/setup.md for the guided + manual install walkthrough and docs/troubleshooting.md for common fixes.",
|
|
38
58
|
:green
|
|
@@ -40,6 +60,86 @@ module SourceMonitor
|
|
|
40
60
|
|
|
41
61
|
private
|
|
42
62
|
|
|
63
|
+
RECURRING_ENTRIES = {
|
|
64
|
+
"source_monitor_schedule_fetches" => {
|
|
65
|
+
"class" => "SourceMonitor::ScheduleFetchesJob",
|
|
66
|
+
"args" => [ { "limit" => 100 } ],
|
|
67
|
+
"schedule" => "every minute"
|
|
68
|
+
},
|
|
69
|
+
"source_monitor_schedule_scrapes" => {
|
|
70
|
+
"command" => "SourceMonitor::Scraping::Scheduler.run(limit: 100)",
|
|
71
|
+
"schedule" => "every 2 minutes"
|
|
72
|
+
},
|
|
73
|
+
"source_monitor_item_cleanup" => {
|
|
74
|
+
"class" => "SourceMonitor::ItemCleanupJob",
|
|
75
|
+
"schedule" => "at 2am every day"
|
|
76
|
+
},
|
|
77
|
+
"source_monitor_log_cleanup" => {
|
|
78
|
+
"class" => "SourceMonitor::LogCleanupJob",
|
|
79
|
+
"args" => [ { "fetch_logs_older_than_days" => 90, "scrape_logs_older_than_days" => 60 } ],
|
|
80
|
+
"schedule" => "at 3am every day"
|
|
81
|
+
}
|
|
82
|
+
}.freeze
|
|
83
|
+
|
|
84
|
+
def recurring_file_has_source_monitor_entries?(path)
|
|
85
|
+
return false unless File.exist?(path)
|
|
86
|
+
|
|
87
|
+
content = File.read(path)
|
|
88
|
+
content.include?("source_monitor_schedule_fetches")
|
|
89
|
+
end
|
|
90
|
+
|
|
91
|
+
def merge_into_existing_recurring(destination, recurring_path)
|
|
92
|
+
parsed = YAML.safe_load(File.read(destination), aliases: true) || {}
|
|
93
|
+
default_key = parsed.key?("default") ? "default" : nil
|
|
94
|
+
|
|
95
|
+
if default_key
|
|
96
|
+
parsed["default"] = (parsed["default"] || {}).merge(RECURRING_ENTRIES)
|
|
97
|
+
else
|
|
98
|
+
parsed.merge!(RECURRING_ENTRIES)
|
|
99
|
+
end
|
|
100
|
+
|
|
101
|
+
write_recurring_yaml(destination, parsed, has_environments: parsed.key?("development"))
|
|
102
|
+
say_status :append, recurring_path, :green
|
|
103
|
+
end
|
|
104
|
+
|
|
105
|
+
def create_recurring_file(destination, recurring_path)
|
|
106
|
+
FileUtils.mkdir_p(File.dirname(destination))
|
|
107
|
+
yaml_content = build_fresh_recurring_yaml
|
|
108
|
+
File.write(destination, yaml_content)
|
|
109
|
+
say_status :create, recurring_path, :green
|
|
110
|
+
end
|
|
111
|
+
|
|
112
|
+
def build_fresh_recurring_yaml
|
|
113
|
+
entries_yaml = format_entries_yaml(RECURRING_ENTRIES)
|
|
114
|
+
|
|
115
|
+
"default: &default\n#{entries_yaml}\n" \
|
|
116
|
+
"development:\n <<: *default\n\n" \
|
|
117
|
+
"test:\n <<: *default\n\n" \
|
|
118
|
+
"production:\n <<: *default\n"
|
|
119
|
+
end
|
|
120
|
+
|
|
121
|
+
def write_recurring_yaml(destination, parsed, has_environments: false)
|
|
122
|
+
if has_environments
|
|
123
|
+
default_entries = parsed["default"] || {}
|
|
124
|
+
entries_yaml = format_entries_yaml(default_entries)
|
|
125
|
+
envs = %w[development test production].select { |e| parsed.key?(e) }
|
|
126
|
+
env_sections = envs.map { |e| "#{e}:\n <<: *default" }.join("\n\n")
|
|
127
|
+
|
|
128
|
+
content = "default: &default\n#{entries_yaml}"
|
|
129
|
+
content += "\n#{env_sections}\n" unless envs.empty?
|
|
130
|
+
File.write(destination, content)
|
|
131
|
+
else
|
|
132
|
+
File.write(destination, YAML.dump(parsed))
|
|
133
|
+
end
|
|
134
|
+
end
|
|
135
|
+
|
|
136
|
+
def format_entries_yaml(entries)
|
|
137
|
+
entries.map { |key, value|
|
|
138
|
+
entry = YAML.dump({ key => value }).delete_prefix("---\n")
|
|
139
|
+
entry.gsub(/^/, " ")
|
|
140
|
+
}.join("\n")
|
|
141
|
+
end
|
|
142
|
+
|
|
43
143
|
def engine_already_mounted?(mount_path)
|
|
44
144
|
routes_path = File.join(destination_root, "config/routes.rb")
|
|
45
145
|
return false unless File.exist?(routes_path)
|
|
@@ -0,0 +1,94 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
require "fileutils"
|
|
4
|
+
require "pathname"
|
|
5
|
+
|
|
6
|
+
module SourceMonitor
|
|
7
|
+
module Setup
|
|
8
|
+
class SkillsInstaller
|
|
9
|
+
SM_SKILL_PATTERN = "sm-*"
|
|
10
|
+
|
|
11
|
+
CONSUMER_SKILLS = %w[
|
|
12
|
+
sm-host-setup sm-configure sm-scraper-adapter
|
|
13
|
+
sm-event-handler sm-model-extension sm-dashboard-widget
|
|
14
|
+
].freeze
|
|
15
|
+
|
|
16
|
+
CONTRIBUTOR_SKILLS = %w[
|
|
17
|
+
sm-domain-model sm-architecture sm-engine-test
|
|
18
|
+
sm-configuration-setting sm-pipeline-stage sm-engine-migration
|
|
19
|
+
sm-job sm-health-rule
|
|
20
|
+
].freeze
|
|
21
|
+
|
|
22
|
+
def initialize(gem_root: nil, output: $stdout)
|
|
23
|
+
@gem_root = Pathname.new(gem_root || resolve_gem_root)
|
|
24
|
+
@output = output
|
|
25
|
+
end
|
|
26
|
+
|
|
27
|
+
def install(target_dir:, group: :consumer)
|
|
28
|
+
target = Pathname.new(target_dir)
|
|
29
|
+
result = { installed: [], skipped: [] }
|
|
30
|
+
|
|
31
|
+
source_skills_dir = gem_root.join(".claude", "skills")
|
|
32
|
+
return result unless source_skills_dir.directory?
|
|
33
|
+
|
|
34
|
+
skill_dirs = Dir[source_skills_dir.join(SM_SKILL_PATTERN).to_s].sort
|
|
35
|
+
return result if skill_dirs.empty?
|
|
36
|
+
|
|
37
|
+
allowed = skills_for_group(group)
|
|
38
|
+
skill_dirs = skill_dirs.select { |path| allowed.include?(File.basename(path)) }
|
|
39
|
+
return result if skill_dirs.empty?
|
|
40
|
+
|
|
41
|
+
FileUtils.mkdir_p(target.to_s)
|
|
42
|
+
|
|
43
|
+
skill_dirs.each do |source_path|
|
|
44
|
+
skill_name = File.basename(source_path)
|
|
45
|
+
dest_path = target.join(skill_name)
|
|
46
|
+
|
|
47
|
+
if dest_path.directory?
|
|
48
|
+
result[:skipped] << skill_name
|
|
49
|
+
else
|
|
50
|
+
FileUtils.cp_r(source_path, dest_path.to_s)
|
|
51
|
+
result[:installed] << skill_name
|
|
52
|
+
end
|
|
53
|
+
end
|
|
54
|
+
|
|
55
|
+
result
|
|
56
|
+
end
|
|
57
|
+
|
|
58
|
+
def remove(target_dir:)
|
|
59
|
+
target = Pathname.new(target_dir)
|
|
60
|
+
result = { removed: [] }
|
|
61
|
+
|
|
62
|
+
return result unless target.directory?
|
|
63
|
+
|
|
64
|
+
Dir[target.join(SM_SKILL_PATTERN).to_s].sort.each do |path|
|
|
65
|
+
skill_name = File.basename(path)
|
|
66
|
+
FileUtils.rm_rf(path)
|
|
67
|
+
result[:removed] << skill_name
|
|
68
|
+
end
|
|
69
|
+
|
|
70
|
+
result
|
|
71
|
+
end
|
|
72
|
+
|
|
73
|
+
private
|
|
74
|
+
|
|
75
|
+
attr_reader :gem_root, :output
|
|
76
|
+
|
|
77
|
+
def skills_for_group(group)
|
|
78
|
+
case group
|
|
79
|
+
when :consumer then CONSUMER_SKILLS
|
|
80
|
+
when :contributor then CONTRIBUTOR_SKILLS
|
|
81
|
+
when :all then CONSUMER_SKILLS + CONTRIBUTOR_SKILLS
|
|
82
|
+
else raise ArgumentError, "Unknown skill group: #{group.inspect}. Use :consumer, :contributor, or :all"
|
|
83
|
+
end
|
|
84
|
+
end
|
|
85
|
+
|
|
86
|
+
def resolve_gem_root
|
|
87
|
+
spec = Gem.loaded_specs["source_monitor"]
|
|
88
|
+
return spec.gem_dir if spec
|
|
89
|
+
|
|
90
|
+
File.expand_path("../../..", __dir__)
|
|
91
|
+
end
|
|
92
|
+
end
|
|
93
|
+
end
|
|
94
|
+
end
|
metadata
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
|
2
2
|
name: source_monitor
|
|
3
3
|
version: !ruby/object:Gem::Version
|
|
4
|
-
version: 0.3.
|
|
4
|
+
version: 0.3.3
|
|
5
5
|
platform: ruby
|
|
6
6
|
authors:
|
|
7
7
|
- dchuk
|
|
@@ -238,6 +238,8 @@ executables: []
|
|
|
238
238
|
extensions: []
|
|
239
239
|
extra_rdoc_files: []
|
|
240
240
|
files:
|
|
241
|
+
- ".claude/agent-memory/vbw-vbw-dev/MEMORY.md"
|
|
242
|
+
- ".claude/agent-memory/vbw-vbw-lead/MEMORY.md"
|
|
241
243
|
- ".claude/agents/rails-concern.md"
|
|
242
244
|
- ".claude/agents/rails-controller.md"
|
|
243
245
|
- ".claude/agents/rails-hotwire.md"
|
|
@@ -256,6 +258,7 @@ files:
|
|
|
256
258
|
- ".claude/agents/rails-tdd.md"
|
|
257
259
|
- ".claude/agents/rails-test.md"
|
|
258
260
|
- ".claude/agents/rails-view-component.md"
|
|
261
|
+
- ".claude/commands/release.md"
|
|
259
262
|
- ".claude/hooks/block-secrets.sh"
|
|
260
263
|
- ".claude/settings.json"
|
|
261
264
|
- ".claude/skills/action-cable-patterns/SKILL.md"
|
|
@@ -336,8 +339,6 @@ files:
|
|
|
336
339
|
- ".gitignore"
|
|
337
340
|
- ".rubocop.yml"
|
|
338
341
|
- ".ruby-version"
|
|
339
|
-
- ".vbw-planning/.notification-log.jsonl"
|
|
340
|
-
- ".vbw-planning/.session-log.jsonl"
|
|
341
342
|
- ".vbw-planning/PROJECT.md"
|
|
342
343
|
- ".vbw-planning/REQUIREMENTS.md"
|
|
343
344
|
- ".vbw-planning/SHIPPED.md"
|
|
@@ -395,6 +396,7 @@ files:
|
|
|
395
396
|
- MIT-LICENSE
|
|
396
397
|
- README.md
|
|
397
398
|
- Rakefile
|
|
399
|
+
- VERSION
|
|
398
400
|
- app/assets/builds/.keep
|
|
399
401
|
- app/assets/builds/source_monitor/application.css
|
|
400
402
|
- app/assets/builds/source_monitor/application.js
|
|
@@ -642,6 +644,7 @@ files:
|
|
|
642
644
|
- lib/source_monitor/setup/prompter.rb
|
|
643
645
|
- lib/source_monitor/setup/requirements.rb
|
|
644
646
|
- lib/source_monitor/setup/shell_runner.rb
|
|
647
|
+
- lib/source_monitor/setup/skills_installer.rb
|
|
645
648
|
- lib/source_monitor/setup/verification/action_cable_verifier.rb
|
|
646
649
|
- lib/source_monitor/setup/verification/printer.rb
|
|
647
650
|
- lib/source_monitor/setup/verification/result.rb
|
|
@@ -1,246 +0,0 @@
|
|
|
1
|
-
{
|
|
2
|
-
"timestamp": "2026-02-09T18:13:43Z",
|
|
3
|
-
"type": "permission_prompt",
|
|
4
|
-
"title": "",
|
|
5
|
-
"message": "Claude Code needs your attention"
|
|
6
|
-
}
|
|
7
|
-
{
|
|
8
|
-
"timestamp": "2026-02-09T18:14:43Z",
|
|
9
|
-
"type": "permission_prompt",
|
|
10
|
-
"title": "",
|
|
11
|
-
"message": "Claude Code needs your attention"
|
|
12
|
-
}
|
|
13
|
-
{
|
|
14
|
-
"timestamp": "2026-02-09T18:26:49Z",
|
|
15
|
-
"type": "permission_prompt",
|
|
16
|
-
"title": "",
|
|
17
|
-
"message": "Claude Code needs your attention"
|
|
18
|
-
}
|
|
19
|
-
{
|
|
20
|
-
"timestamp": "2026-02-09T18:28:21Z",
|
|
21
|
-
"type": "permission_prompt",
|
|
22
|
-
"title": "",
|
|
23
|
-
"message": "Claude Code needs your attention"
|
|
24
|
-
}
|
|
25
|
-
{
|
|
26
|
-
"timestamp": "2026-02-09T19:21:16Z",
|
|
27
|
-
"type": "permission_prompt",
|
|
28
|
-
"title": "",
|
|
29
|
-
"message": "Claude Code needs your attention"
|
|
30
|
-
}
|
|
31
|
-
{
|
|
32
|
-
"timestamp": "2026-02-09T19:35:42Z",
|
|
33
|
-
"type": "idle_prompt",
|
|
34
|
-
"title": "",
|
|
35
|
-
"message": "Claude is waiting for your input"
|
|
36
|
-
}
|
|
37
|
-
{
|
|
38
|
-
"timestamp": "2026-02-09T19:41:08Z",
|
|
39
|
-
"type": "idle_prompt",
|
|
40
|
-
"title": "",
|
|
41
|
-
"message": "Claude is waiting for your input"
|
|
42
|
-
}
|
|
43
|
-
{
|
|
44
|
-
"timestamp": "2026-02-09T19:50:34Z",
|
|
45
|
-
"type": "idle_prompt",
|
|
46
|
-
"title": "",
|
|
47
|
-
"message": "Claude is waiting for your input"
|
|
48
|
-
}
|
|
49
|
-
{
|
|
50
|
-
"timestamp": "2026-02-09T19:54:13Z",
|
|
51
|
-
"type": "idle_prompt",
|
|
52
|
-
"title": "",
|
|
53
|
-
"message": "Claude is waiting for your input"
|
|
54
|
-
}
|
|
55
|
-
{
|
|
56
|
-
"timestamp": "2026-02-09T20:42:45Z",
|
|
57
|
-
"type": "idle_prompt",
|
|
58
|
-
"title": "",
|
|
59
|
-
"message": "Claude is waiting for your input"
|
|
60
|
-
}
|
|
61
|
-
{
|
|
62
|
-
"timestamp": "2026-02-10T15:38:42Z",
|
|
63
|
-
"type": "idle_prompt",
|
|
64
|
-
"title": "",
|
|
65
|
-
"message": "Claude is waiting for your input"
|
|
66
|
-
}
|
|
67
|
-
{
|
|
68
|
-
"timestamp": "2026-02-10T16:14:26Z",
|
|
69
|
-
"type": "idle_prompt",
|
|
70
|
-
"title": "",
|
|
71
|
-
"message": "Claude is waiting for your input"
|
|
72
|
-
}
|
|
73
|
-
{
|
|
74
|
-
"timestamp": "2026-02-10T16:20:58Z",
|
|
75
|
-
"type": "idle_prompt",
|
|
76
|
-
"title": "",
|
|
77
|
-
"message": "Claude is waiting for your input"
|
|
78
|
-
}
|
|
79
|
-
{
|
|
80
|
-
"timestamp": "2026-02-10T16:35:17Z",
|
|
81
|
-
"type": "idle_prompt",
|
|
82
|
-
"title": "",
|
|
83
|
-
"message": "Claude is waiting for your input"
|
|
84
|
-
}
|
|
85
|
-
{
|
|
86
|
-
"timestamp": "2026-02-10T16:46:01Z",
|
|
87
|
-
"type": "idle_prompt",
|
|
88
|
-
"title": "",
|
|
89
|
-
"message": "Claude is waiting for your input"
|
|
90
|
-
}
|
|
91
|
-
{
|
|
92
|
-
"timestamp": "2026-02-10T17:15:18Z",
|
|
93
|
-
"type": "permission_prompt",
|
|
94
|
-
"title": "",
|
|
95
|
-
"message": "Claude Code needs your attention"
|
|
96
|
-
}
|
|
97
|
-
{
|
|
98
|
-
"timestamp": "2026-02-10T17:25:59Z",
|
|
99
|
-
"type": "idle_prompt",
|
|
100
|
-
"title": "",
|
|
101
|
-
"message": "Claude is waiting for your input"
|
|
102
|
-
}
|
|
103
|
-
{
|
|
104
|
-
"timestamp": "2026-02-10T17:49:24Z",
|
|
105
|
-
"type": "idle_prompt",
|
|
106
|
-
"title": "",
|
|
107
|
-
"message": "Claude is waiting for your input"
|
|
108
|
-
}
|
|
109
|
-
{
|
|
110
|
-
"timestamp": "2026-02-10T17:51:32Z",
|
|
111
|
-
"type": "idle_prompt",
|
|
112
|
-
"title": "",
|
|
113
|
-
"message": "Claude is waiting for your input"
|
|
114
|
-
}
|
|
115
|
-
{
|
|
116
|
-
"timestamp": "2026-02-10T18:00:59Z",
|
|
117
|
-
"type": "idle_prompt",
|
|
118
|
-
"title": "",
|
|
119
|
-
"message": "Claude is waiting for your input"
|
|
120
|
-
}
|
|
121
|
-
{
|
|
122
|
-
"timestamp": "2026-02-10T18:03:48Z",
|
|
123
|
-
"type": "idle_prompt",
|
|
124
|
-
"title": "",
|
|
125
|
-
"message": "Claude is waiting for your input"
|
|
126
|
-
}
|
|
127
|
-
{
|
|
128
|
-
"timestamp": "2026-02-10T18:06:56Z",
|
|
129
|
-
"type": "idle_prompt",
|
|
130
|
-
"title": "",
|
|
131
|
-
"message": "Claude is waiting for your input"
|
|
132
|
-
}
|
|
133
|
-
{
|
|
134
|
-
"timestamp": "2026-02-10T18:23:05Z",
|
|
135
|
-
"type": "permission_prompt",
|
|
136
|
-
"title": "",
|
|
137
|
-
"message": "Claude Code needs your attention"
|
|
138
|
-
}
|
|
139
|
-
{
|
|
140
|
-
"timestamp": "2026-02-10T22:13:49Z",
|
|
141
|
-
"type": "permission_prompt",
|
|
142
|
-
"title": "",
|
|
143
|
-
"message": "Claude Code needs your attention"
|
|
144
|
-
}
|
|
145
|
-
{
|
|
146
|
-
"timestamp": "2026-02-10T23:25:19Z",
|
|
147
|
-
"type": "idle_prompt",
|
|
148
|
-
"title": "",
|
|
149
|
-
"message": "Claude is waiting for your input"
|
|
150
|
-
}
|
|
151
|
-
{
|
|
152
|
-
"timestamp": "2026-02-10T23:28:33Z",
|
|
153
|
-
"type": "idle_prompt",
|
|
154
|
-
"title": "",
|
|
155
|
-
"message": "Claude is waiting for your input"
|
|
156
|
-
}
|
|
157
|
-
{
|
|
158
|
-
"timestamp": "2026-02-10T23:48:00Z",
|
|
159
|
-
"type": "idle_prompt",
|
|
160
|
-
"title": "",
|
|
161
|
-
"message": "Claude is waiting for your input"
|
|
162
|
-
}
|
|
163
|
-
{
|
|
164
|
-
"timestamp": "2026-02-10T23:50:02Z",
|
|
165
|
-
"type": "idle_prompt",
|
|
166
|
-
"title": "",
|
|
167
|
-
"message": "Claude is waiting for your input"
|
|
168
|
-
}
|
|
169
|
-
{
|
|
170
|
-
"timestamp": "2026-02-10T23:59:29Z",
|
|
171
|
-
"type": "idle_prompt",
|
|
172
|
-
"title": "",
|
|
173
|
-
"message": "Claude is waiting for your input"
|
|
174
|
-
}
|
|
175
|
-
{
|
|
176
|
-
"timestamp": "2026-02-11T00:00:52Z",
|
|
177
|
-
"type": "idle_prompt",
|
|
178
|
-
"title": "",
|
|
179
|
-
"message": "Claude is waiting for your input"
|
|
180
|
-
}
|
|
181
|
-
{
|
|
182
|
-
"timestamp": "2026-02-11T00:05:52Z",
|
|
183
|
-
"type": "permission_prompt",
|
|
184
|
-
"title": "",
|
|
185
|
-
"message": "Claude Code needs your attention"
|
|
186
|
-
}
|
|
187
|
-
{
|
|
188
|
-
"timestamp": "2026-02-11T00:23:40Z",
|
|
189
|
-
"type": "permission_prompt",
|
|
190
|
-
"title": "",
|
|
191
|
-
"message": "Claude Code needs your attention"
|
|
192
|
-
}
|
|
193
|
-
{
|
|
194
|
-
"timestamp": "2026-02-11T00:46:04Z",
|
|
195
|
-
"type": "idle_prompt",
|
|
196
|
-
"title": "",
|
|
197
|
-
"message": "Claude is waiting for your input"
|
|
198
|
-
}
|
|
199
|
-
{
|
|
200
|
-
"timestamp": "2026-02-11T00:59:14Z",
|
|
201
|
-
"type": "idle_prompt",
|
|
202
|
-
"title": "",
|
|
203
|
-
"message": "Claude is waiting for your input"
|
|
204
|
-
}
|
|
205
|
-
{
|
|
206
|
-
"timestamp": "2026-02-11T03:26:32Z",
|
|
207
|
-
"type": "idle_prompt",
|
|
208
|
-
"title": "",
|
|
209
|
-
"message": "Claude is waiting for your input"
|
|
210
|
-
}
|
|
211
|
-
{
|
|
212
|
-
"timestamp": "2026-02-11T03:46:35Z",
|
|
213
|
-
"type": "idle_prompt",
|
|
214
|
-
"title": "",
|
|
215
|
-
"message": "Claude is waiting for your input"
|
|
216
|
-
}
|
|
217
|
-
{
|
|
218
|
-
"timestamp": "2026-02-11T04:21:35Z",
|
|
219
|
-
"type": "permission_prompt",
|
|
220
|
-
"title": "",
|
|
221
|
-
"message": "Claude Code needs your attention"
|
|
222
|
-
}
|
|
223
|
-
{
|
|
224
|
-
"timestamp": "2026-02-11T04:28:53Z",
|
|
225
|
-
"type": "permission_prompt",
|
|
226
|
-
"title": "",
|
|
227
|
-
"message": "Claude Code needs your approval for the plan"
|
|
228
|
-
}
|
|
229
|
-
{
|
|
230
|
-
"timestamp": "2026-02-11T04:33:09Z",
|
|
231
|
-
"type": "permission_prompt",
|
|
232
|
-
"title": "",
|
|
233
|
-
"message": "Claude Code needs your approval for the plan"
|
|
234
|
-
}
|
|
235
|
-
{
|
|
236
|
-
"timestamp": "2026-02-11T04:46:56Z",
|
|
237
|
-
"type": "idle_prompt",
|
|
238
|
-
"title": "",
|
|
239
|
-
"message": "Claude is waiting for your input"
|
|
240
|
-
}
|
|
241
|
-
{
|
|
242
|
-
"timestamp": "2026-02-11T04:55:02Z",
|
|
243
|
-
"type": "permission_prompt",
|
|
244
|
-
"title": "",
|
|
245
|
-
"message": "Claude Code needs your approval for the plan"
|
|
246
|
-
}
|