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.
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.2"
13
- # or add `gem "source_monitor", "~> 0.1.2"` manually, then run:
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 3.4.4 (we recommend [rbenv](https://github.com/rbenv/rbenv) for local development: `rbenv install 3.4.4 && rbenv local 3.4.4`, but use whatever Ruby version manager suits your environment—asdf, chruby, rvm, or container-based workflows all work fine)
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.2"
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 `.ai/project_overview.md`. Review `.ai/tasks.md` to align with the active roadmap slice before opening a pull request.
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 3.3 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.
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 | 3.4.4 | Use rbenv and match the engine's `.ruby-version`. |
10
- | Rails | 8.0.2.1 | Run `bin/rails about` inside the host to confirm. |
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.2"
22
- # or add gem "source_monitor", "~> 0.1.2" to Gemfile manually
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 and create the initializer |
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 prints follow-up instructions. Re-running the generator is safe; it detects existing mounts/initializers.
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). Add a recurring process via `bin/jobs --recurring_schedule_file=config/recurring.yml` when you need fetch/scrape schedules.
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
@@ -1,5 +1,5 @@
1
1
  # frozen_string_literal: true
2
2
 
3
3
  module SourceMonitor
4
- VERSION = "0.3.1"
4
+ VERSION = "0.3.3"
5
5
  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.1
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
- }