coolhand 0.9.0 → 0.10.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 +8 -0
- data/README.md +20 -1
- data/docs/help-center.md +120 -0
- data/lib/coolhand/logger_service.rb +1 -1
- data/lib/coolhand/public_content_service.rb +69 -0
- data/lib/coolhand/read_requests.rb +11 -2
- data/lib/coolhand/version.rb +1 -1
- data/lib/coolhand.rb +7 -0
- metadata +4 -2
checksums.yaml
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
---
|
|
2
2
|
SHA256:
|
|
3
|
-
metadata.gz:
|
|
4
|
-
data.tar.gz:
|
|
3
|
+
metadata.gz: 301fa9e603334f3c6b5349755239cdf06418b9b78f1fae3de44abc352b8f1828
|
|
4
|
+
data.tar.gz: 0b687769a058ff206f50deaf46ad1e28909e7f4e4229d217ad5b36b7350ff9ce
|
|
5
5
|
SHA512:
|
|
6
|
-
metadata.gz:
|
|
7
|
-
data.tar.gz:
|
|
6
|
+
metadata.gz: 9a4653638e2362853b90baf55bc1df97f73ee1144357524c61be21798b58fcffe383d9bbde1b9cb33ac7c9d07064377eff681667be8ed2a341103cdb06ab42ff
|
|
7
|
+
data.tar.gz: 464a1d38d383ebf98f3f42b9f60fccfe65d13fcc3a1ea45d5df0c7fc1f26aad721a9b2650f1c41277a09dbf5a92a24f32f2223f961c9940de592fecf54d1057d
|
data/CHANGELOG.md
CHANGED
|
@@ -7,6 +7,14 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0
|
|
|
7
7
|
|
|
8
8
|
## [Unreleased]
|
|
9
9
|
|
|
10
|
+
## [0.10.0] - 2026-10-21
|
|
11
|
+
|
|
12
|
+
### Added
|
|
13
|
+
- **Read the Coolhand help center** ([#164](https://github.com/Coolhand-Labs/coolhand-ruby/pull/164)) — `Coolhand.public_content_service` wraps the read-only help center endpoints: `search_help_articles(query:, category:, page:, per_page:)` returns a `Coolhand::HelpArticleSearchResult` (`articles`, `pagination`), `get_help_article(slug)` returns one article with its markdown `body` and `toc`, and `list_help_categories` lists the sections. Unlike every other read service it needs **no API key**: with none configured no `X-API-Key` header is sent (anonymous callers are limited to 30 requests per minute per IP), and a configured `config.api_key` is sent and lifts the limit. Like the other read methods, these raise `Coolhand::Error` / `Coolhand::HttpError` rather than logging and returning `nil`. See [Reading the Help Center](docs/help-center.md).
|
|
14
|
+
|
|
15
|
+
### Security
|
|
16
|
+
- `LoggerService#forward_webhook` now redacts credentials (userinfo and sensitive query parameters such as `token=`) in a caller-supplied `url:` before logging it, the same way intercepted request URLs are. **Migration note:** if you pass a `url:` containing such values, they now appear as `[REDACTED]` in Coolhand.
|
|
17
|
+
|
|
10
18
|
## [0.9.0] - 2026-10-18
|
|
11
19
|
|
|
12
20
|
### Added
|
data/README.md
CHANGED
|
@@ -118,6 +118,24 @@ Coolhand.log_service.search_logs(order: 'cost_desc', min_cost: 1.0, per: 10, **w
|
|
|
118
118
|
|
|
119
119
|
See [Reading Workloads →](docs/workload-search.md) and [Reading Logs →](docs/log-search.md).
|
|
120
120
|
|
|
121
|
+
## Reading the Help Center
|
|
122
|
+
|
|
123
|
+
`Coolhand.public_content_service` reads the Coolhand help center (the same pages as coolhandlabs.com/help and /updates) with **no API key required**:
|
|
124
|
+
|
|
125
|
+
```ruby
|
|
126
|
+
require 'coolhand'
|
|
127
|
+
|
|
128
|
+
help_center = Coolhand.public_content_service
|
|
129
|
+
|
|
130
|
+
result = help_center.search_help_articles(query: 'match rate', per_page: 5)
|
|
131
|
+
article = help_center.get_help_article(result.articles.first[:slug]) # full markdown :body
|
|
132
|
+
categories = help_center.list_help_categories
|
|
133
|
+
```
|
|
134
|
+
|
|
135
|
+
Anonymous callers are limited to 30 requests per minute per IP. If `config.api_key` is set it is sent and lifts the limit; a key the server rejects raises a 401 `Coolhand::HttpError`. These are read methods, so they **raise** where the write methods log and return `nil`.
|
|
136
|
+
|
|
137
|
+
See [Reading the Help Center →](docs/help-center.md) for parameters, the category filter and errors.
|
|
138
|
+
|
|
121
139
|
## Linking Feedback to an Optimization
|
|
122
140
|
|
|
123
141
|
Attach feedback to an optimization as evidence, one at a time or in bulk. These require your **private** API key and **raise** `Coolhand::Error` on failure (`Coolhand::HttpError` for non-2xx responses).
|
|
@@ -488,7 +506,7 @@ The monitor handles errors gracefully:
|
|
|
488
506
|
- Failed API logging attempts are logged to console but don't interrupt your application
|
|
489
507
|
- Invalid API keys will be reported but won't crash your app
|
|
490
508
|
- Network issues are handled with appropriate error messages
|
|
491
|
-
- The read methods (`search_templates`, `get_template`, `search_workloads`, `search_logs`, `get_log`), the feedback-link methods and the `upsert` methods are the exception — they raise `Coolhand::Error` (`Coolhand::HttpError` for non-2xx responses); see [Reading Templates →](docs/template-search.md), [Reading Workloads →](docs/workload-search.md), [Reading Logs →](docs/log-search.md), [Linking Feedback →](docs/feedback-links.md) and [Declared Workloads →](docs/declared_workloads.md)
|
|
509
|
+
- The read methods (`search_templates`, `get_template`, `search_workloads`, `search_logs`, `get_log`, `search_help_articles`, `get_help_article`, `list_help_categories`), the feedback-link methods and the `upsert` methods are the exception — they raise `Coolhand::Error` (`Coolhand::HttpError` for non-2xx responses); see [Reading Templates →](docs/template-search.md), [Reading Workloads →](docs/workload-search.md), [Reading Logs →](docs/log-search.md), [Linking Feedback →](docs/feedback-links.md) and [Declared Workloads →](docs/declared_workloads.md)
|
|
492
510
|
|
|
493
511
|
## Documentation
|
|
494
512
|
|
|
@@ -497,6 +515,7 @@ The monitor handles errors gracefully:
|
|
|
497
515
|
- **[Reading Templates](docs/template-search.md)** — Search LLM request templates and fetch a single one, prompt patterns included, using the private API key
|
|
498
516
|
- **[Reading Workloads](docs/workload-search.md)** — List workloads with optional cost and performance metrics over a rolling or explicit time window
|
|
499
517
|
- **[Reading Logs](docs/log-search.md)** — Search logs with per-log cost, filter and sort by cost, and fetch one log with its cost breakdown
|
|
518
|
+
- **[Reading the Help Center](docs/help-center.md)** — Search and read Coolhand's help center articles and list its sections, with no API key required
|
|
500
519
|
- **[Linking Feedback](docs/feedback-links.md)** — Link feedback to an optimization as evidence, singly or in bulk, using the private API key
|
|
501
520
|
- **[Declared Workloads](docs/declared_workloads.md)** — Declare the workload and template of captured LLM calls with `Coolhand.with_context`, and create or rename them with `upsert`
|
|
502
521
|
- **[Anthropic Integration](docs/anthropic.md)** — Official and community Anthropic Ruby gems, streaming, dual gem handling, and troubleshooting
|
data/docs/help-center.md
ADDED
|
@@ -0,0 +1,120 @@
|
|
|
1
|
+
# Reading the Help Center
|
|
2
|
+
|
|
3
|
+
`Coolhand::PublicContentService` reads Coolhand's help center: the articles served at
|
|
4
|
+
`coolhandlabs.com/help/:slug` and the posts at `/updates/:slug`. "Help center" is the user-facing name;
|
|
5
|
+
on the wire the resource is `public_content` (`GET /api/v2/public_content`, `/:slug` and `/categories`).
|
|
6
|
+
It is read-only. Creating, updating and archiving articles is Coolhand-internal and not wrapped.
|
|
7
|
+
|
|
8
|
+
**Auth:** none required. Unlike every other service, no API key is needed:
|
|
9
|
+
|
|
10
|
+
```ruby
|
|
11
|
+
require "coolhand"
|
|
12
|
+
|
|
13
|
+
help_center = Coolhand.public_content_service # works with Coolhand.configure never called
|
|
14
|
+
```
|
|
15
|
+
|
|
16
|
+
- No key configured: no `X-API-Key` header is sent, and the calls work. Anonymous callers are limited to
|
|
17
|
+
**30 requests per minute per IP**; beyond that the server answers `429`.
|
|
18
|
+
- A configured `config.api_key` is sent as `X-API-Key` and callers with a valid key are not rate limited.
|
|
19
|
+
This gem reads the key from configuration only, not from the environment.
|
|
20
|
+
- A key the server does not recognise is a `401` (`{"error":"Invalid API key."}`) even though the endpoint is
|
|
21
|
+
public. It is raised, not retried anonymously.
|
|
22
|
+
|
|
23
|
+
## `search_help_articles`
|
|
24
|
+
|
|
25
|
+
```ruby
|
|
26
|
+
result = help_center.search_help_articles(query: "match rate", category: "feedback-and-prompts", per_page: 10)
|
|
27
|
+
|
|
28
|
+
result.articles.each { |a| puts "#{a[:title]}: #{a[:search_headline]}" }
|
|
29
|
+
result.pagination.total_count
|
|
30
|
+
```
|
|
31
|
+
|
|
32
|
+
### Keywords
|
|
33
|
+
|
|
34
|
+
All optional.
|
|
35
|
+
|
|
36
|
+
| keyword | type | notes |
|
|
37
|
+
|---|---|---|
|
|
38
|
+
| `query` | String | Relevance search (Postgres full text, the same as the website's). Supports quoted phrases, `-exclusions` and `or`. Omit for a full listing. A blank string counts as omitted. |
|
|
39
|
+
| `category` | String | Restrict to one section by slug (see `list_help_categories`). A blank string counts as omitted. |
|
|
40
|
+
| `page` | Integer | 1-based. |
|
|
41
|
+
| `per_page` | Integer | Default 25, max 100, both enforced server-side. |
|
|
42
|
+
|
|
43
|
+
The endpoint has no `category` parameter. `category` is sent in its structured form instead, which also
|
|
44
|
+
moves the relevance search to a different key; the plain `q=...` string and the `q[...]` form cannot be
|
|
45
|
+
mixed:
|
|
46
|
+
|
|
47
|
+
| `query` | `category` | Sent |
|
|
48
|
+
|---|---|---|
|
|
49
|
+
| set | unset | `q=<query>` |
|
|
50
|
+
| unset | set | `q[help_category_slug_eq]=<category>` |
|
|
51
|
+
| set | set | `q[help_category_slug_eq]=<category>&q[full_text]=<query>` |
|
|
52
|
+
|
|
53
|
+
### Return value
|
|
54
|
+
|
|
55
|
+
A `Coolhand::HelpArticleSearchResult` with `articles` (an Array of Symbol-keyed Hashes) and `pagination`.
|
|
56
|
+
Each article is a summary; the markdown `:body` is omitted from lists:
|
|
57
|
+
|
|
58
|
+
```ruby
|
|
59
|
+
{
|
|
60
|
+
slug: "what-is-feedback-match-rate",
|
|
61
|
+
title: "What is feedback match rate?",
|
|
62
|
+
answer: "Match rate is the share of ...", # String or nil
|
|
63
|
+
article_kind: "concept", # reference | concept | how_to | troubleshooting | faq_answer | release_note
|
|
64
|
+
tags: ["feedback", "matching"],
|
|
65
|
+
category: "feedback-and-prompts", # section slug
|
|
66
|
+
url: "https://coolhandlabs.com/help/what-is-feedback-match-rate",
|
|
67
|
+
markdown_url: "https://coolhandlabs.com/help/what-is-feedback-match-rate.md",
|
|
68
|
+
reading_time_minutes: 10, # Integer or nil
|
|
69
|
+
search_headline: "<mark>Match</mark> rate ...", # nil on a plain listing
|
|
70
|
+
published_at: "2026-08-30T13:57:52Z", # String or nil
|
|
71
|
+
updated_content_at: "2026-08-30T13:57:52Z" # String or nil
|
|
72
|
+
}
|
|
73
|
+
```
|
|
74
|
+
|
|
75
|
+
`:search_headline` is the matching passage with `<mark>` tags around the matched terms, so you can see
|
|
76
|
+
why something matched without fetching the body.
|
|
77
|
+
|
|
78
|
+
`pagination` is a `Coolhand::Pagination`, the same as the other read methods, built from the `X-Page`,
|
|
79
|
+
`X-Per-Page`, `X-Total-Count` and `X-Total-Pages` response headers (`current_page`, `per_page`,
|
|
80
|
+
`total_count`, `total_pages`, `has_next_page`, `has_prev_page`).
|
|
81
|
+
|
|
82
|
+
## `get_help_article(slug)`
|
|
83
|
+
|
|
84
|
+
```ruby
|
|
85
|
+
article = help_center.get_help_article("what-is-feedback-match-rate")
|
|
86
|
+
article[:body] # full markdown
|
|
87
|
+
article[:toc] # [{ id:, text:, level:, children: }]
|
|
88
|
+
```
|
|
89
|
+
|
|
90
|
+
Returns a Hash: the summary fields minus `:search_headline`, plus `:body` (full markdown), `:noindex`
|
|
91
|
+
(Boolean) and `:toc` (the heading structure, h3s nested under their h2). The slug is escaped as a single
|
|
92
|
+
path segment. Raises `Coolhand::Error` before any request if `slug` is blank or a bare `.`/`..`. An unknown
|
|
93
|
+
or unpublished slug raises `Coolhand::HttpError` with `status` 404.
|
|
94
|
+
|
|
95
|
+
## `list_help_categories`
|
|
96
|
+
|
|
97
|
+
```ruby
|
|
98
|
+
help_center.list_help_categories
|
|
99
|
+
# [{ slug: "providers", name: "Provider guides", description: "...", url_prefix: "/help", allowed_tags: nil }, ...]
|
|
100
|
+
```
|
|
101
|
+
|
|
102
|
+
Returns an Array of Hashes: `:slug` (the `category` filter above), `:name`, `:description`, `:url_prefix`
|
|
103
|
+
(`/help` or `/updates`) and `:allowed_tags` (the only tags the section accepts; `nil` means any tag).
|
|
104
|
+
|
|
105
|
+
## Errors
|
|
106
|
+
|
|
107
|
+
These are read methods, so they raise where the logging writes log and return `nil`. A network failure or
|
|
108
|
+
a non-JSON body raises `Coolhand::Error`. A non-2xx response raises `Coolhand::HttpError`, whose `status`
|
|
109
|
+
holds the HTTP status code and `body` the (truncated) response body: `401` for an invalid key, `404` for an
|
|
110
|
+
unknown slug, `429` when the anonymous rate limit is exceeded.
|
|
111
|
+
|
|
112
|
+
## Verifying against a live server
|
|
113
|
+
|
|
114
|
+
`spec/live/coolhand_public_content_live_spec.rb` runs against a real server with no key:
|
|
115
|
+
|
|
116
|
+
```bash
|
|
117
|
+
COOLHAND_SPEC_LIVE_BASE_URL=http://127.0.0.1:3000/api bundle exec rspec spec/live/coolhand_public_content_live_spec.rb
|
|
118
|
+
```
|
|
119
|
+
|
|
120
|
+
It makes about nine anonymous requests, so running it repeatedly within a minute can hit the `429`.
|
|
@@ -24,7 +24,7 @@ module Coolhand
|
|
|
24
24
|
id: options[:id] || SecureRandom.uuid,
|
|
25
25
|
timestamp: options[:timestamp] || Time.now.utc.strftime("%Y-%m-%dT%H:%M:%S.%6NZ"),
|
|
26
26
|
method: options[:method] || "POST",
|
|
27
|
-
url: options[:url] || build_webhook_url(source, event_type),
|
|
27
|
+
url: BaseInterceptor.sanitize_url(options[:url] || build_webhook_url(source, event_type)),
|
|
28
28
|
headers: sanitize_headers(headers),
|
|
29
29
|
request_body: clean_webhook_body(webhook_body, source),
|
|
30
30
|
response_body: options[:response_body],
|
|
@@ -0,0 +1,69 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
require_relative "api_service"
|
|
4
|
+
require_relative "pagination"
|
|
5
|
+
require_relative "read_query"
|
|
6
|
+
|
|
7
|
+
module Coolhand
|
|
8
|
+
# Rows stay plain Symbol-keyed Hashes so a field the server adds later is not dropped in transit.
|
|
9
|
+
HelpArticleSearchResult = Struct.new(:articles, :pagination, keyword_init: true)
|
|
10
|
+
|
|
11
|
+
# Read-only access to the Coolhand help center: the `public_content` endpoints (`GET /api/v2/public_content`,
|
|
12
|
+
# `/:slug` and `/categories`), the same pages served at `/help/:slug` and `/updates/:slug`. Create, update and
|
|
13
|
+
# archive are Coolhand-internal and not wrapped.
|
|
14
|
+
#
|
|
15
|
+
# Unlike every other service this one needs no API key. A configured `api_key` is sent as `X-API-Key` and lifts
|
|
16
|
+
# the anonymous limit of 30 requests per minute per IP (429 beyond); with none, no key header is sent. A key the
|
|
17
|
+
# server rejects raises a 401 {Coolhand::HttpError}; it is not retried anonymously. See docs/help-center.md.
|
|
18
|
+
class PublicContentService < ApiService
|
|
19
|
+
include ReadQuery
|
|
20
|
+
|
|
21
|
+
ERROR_NOUN = "Help center"
|
|
22
|
+
BLANK_SLUG_MESSAGE = "get_help_article: slug must be a non-empty string"
|
|
23
|
+
|
|
24
|
+
def initialize
|
|
25
|
+
super("v2/public_content")
|
|
26
|
+
end
|
|
27
|
+
|
|
28
|
+
# Relevance search with `query`, a full listing without. `category` filters to one section slug; the
|
|
29
|
+
# endpoint has no such parameter, so it is sent as `q[help_category_slug_eq]` and `query` moves to
|
|
30
|
+
# `q[full_text]` (the plain `q` string and the `q[...]` form cannot be mixed). A blank `query` or
|
|
31
|
+
# `category` counts as omitted. Returns a {HelpArticleSearchResult}; raises {Coolhand::HttpError} on a
|
|
32
|
+
# non-2xx response.
|
|
33
|
+
def search_help_articles(query: nil, category: nil, page: nil, per_page: nil)
|
|
34
|
+
params = { **search_params(query, category), page: page, per_page: per_page }.compact
|
|
35
|
+
|
|
36
|
+
fetch_list(params, HelpArticleSearchResult, :articles, page: page, per: per_page)
|
|
37
|
+
end
|
|
38
|
+
|
|
39
|
+
# One published article with its markdown `body`, `noindex` and `toc`. Raises {Coolhand::Error} before any
|
|
40
|
+
# request for a blank slug, and {Coolhand::HttpError} (404) for an unknown or unpublished one.
|
|
41
|
+
def get_help_article(slug)
|
|
42
|
+
get_json(resource_url(slug, BLANK_SLUG_MESSAGE), ERROR_NOUN)
|
|
43
|
+
end
|
|
44
|
+
|
|
45
|
+
# Every section an article can be filed under, with its `url_prefix` and `allowed_tags`.
|
|
46
|
+
def list_help_categories
|
|
47
|
+
get_json(URI.parse("#{api_endpoint}/categories"), ERROR_NOUN)
|
|
48
|
+
end
|
|
49
|
+
|
|
50
|
+
protected
|
|
51
|
+
|
|
52
|
+
def api_key_required?
|
|
53
|
+
false
|
|
54
|
+
end
|
|
55
|
+
|
|
56
|
+
private
|
|
57
|
+
|
|
58
|
+
def search_params(query, category)
|
|
59
|
+
query = nil if omitted?(query)
|
|
60
|
+
return { q: query } if omitted?(category)
|
|
61
|
+
|
|
62
|
+
{ "q[help_category_slug_eq]": category, "q[full_text]": query }
|
|
63
|
+
end
|
|
64
|
+
|
|
65
|
+
def omitted?(value)
|
|
66
|
+
value.nil? || value.to_s.strip.empty?
|
|
67
|
+
end
|
|
68
|
+
end
|
|
69
|
+
end
|
|
@@ -29,7 +29,9 @@ module Coolhand
|
|
|
29
29
|
|
|
30
30
|
# Also returns the response, for endpoints that carry pagination in headers rather than the body.
|
|
31
31
|
def get_json_with_headers(url, noun)
|
|
32
|
-
|
|
32
|
+
if api_key_required? && !Coolhand.required_field?(api_key)
|
|
33
|
+
raise Error, "#{noun} request failed: an API key is required"
|
|
34
|
+
end
|
|
33
35
|
|
|
34
36
|
response = perform_get(url, noun)
|
|
35
37
|
|
|
@@ -38,6 +40,11 @@ module Coolhand
|
|
|
38
40
|
[parse_json_body(response.body, noun), response]
|
|
39
41
|
end
|
|
40
42
|
|
|
43
|
+
# Overridden by services over public endpoints, which work anonymously and send the key only if set.
|
|
44
|
+
def api_key_required?
|
|
45
|
+
true
|
|
46
|
+
end
|
|
47
|
+
|
|
41
48
|
private
|
|
42
49
|
|
|
43
50
|
def perform_get(url, noun)
|
|
@@ -45,7 +52,9 @@ module Coolhand
|
|
|
45
52
|
http = build_http(uri)
|
|
46
53
|
|
|
47
54
|
request = Net::HTTP::Get.new(uri.request_uri)
|
|
48
|
-
|
|
55
|
+
headers = { "Accept" => "application/json" }
|
|
56
|
+
headers["X-API-Key"] = api_key if Coolhand.required_field?(api_key)
|
|
57
|
+
apply_headers(request, headers)
|
|
49
58
|
|
|
50
59
|
# Net::HTTP does not follow redirects, so a 3xx raises rather than replaying the API key at
|
|
51
60
|
# an unapproved host. without_capture is the same recursion guard send_request uses.
|
data/lib/coolhand/version.rb
CHANGED
data/lib/coolhand.rb
CHANGED
|
@@ -22,6 +22,7 @@ require_relative "coolhand/feedback_service"
|
|
|
22
22
|
require_relative "coolhand/template_service"
|
|
23
23
|
require_relative "coolhand/optimization_feedback_link_service"
|
|
24
24
|
require_relative "coolhand/workload_service"
|
|
25
|
+
require_relative "coolhand/public_content_service"
|
|
25
26
|
require_relative "coolhand/log_service"
|
|
26
27
|
require_relative "coolhand/webhook_interceptor"
|
|
27
28
|
# Only when Rails is already loaded; the gem has no Rails dependency.
|
|
@@ -147,6 +148,12 @@ module Coolhand
|
|
|
147
148
|
LogService.new
|
|
148
149
|
end
|
|
149
150
|
|
|
151
|
+
# Creates a new PublicContentService, for reading the Coolhand help center. Needs no API key; a
|
|
152
|
+
# configured one is sent and lifts the anonymous rate limit.
|
|
153
|
+
def public_content_service
|
|
154
|
+
PublicContentService.new
|
|
155
|
+
end
|
|
156
|
+
|
|
150
157
|
# Creates a new OptimizationFeedbackLinkService instance, for linking feedback to an
|
|
151
158
|
# optimization as evidence. Needs the private API key.
|
|
152
159
|
def optimization_feedback_link_service
|
metadata
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
|
2
2
|
name: coolhand
|
|
3
3
|
version: !ruby/object:Gem::Version
|
|
4
|
-
version: 0.
|
|
4
|
+
version: 0.10.0
|
|
5
5
|
platform: ruby
|
|
6
6
|
authors:
|
|
7
7
|
- Michael Carroll
|
|
@@ -9,7 +9,7 @@ authors:
|
|
|
9
9
|
autorequire:
|
|
10
10
|
bindir: exe
|
|
11
11
|
cert_chain: []
|
|
12
|
-
date: 2026-10-
|
|
12
|
+
date: 2026-10-21 00:00:00.000000000 Z
|
|
13
13
|
dependencies:
|
|
14
14
|
- !ruby/object:Gem::Dependency
|
|
15
15
|
name: base64
|
|
@@ -51,6 +51,7 @@ files:
|
|
|
51
51
|
- docs/elevenlabs.md
|
|
52
52
|
- docs/feedback-links.md
|
|
53
53
|
- docs/feedback.md
|
|
54
|
+
- docs/help-center.md
|
|
54
55
|
- docs/log-search.md
|
|
55
56
|
- docs/openai.md
|
|
56
57
|
- docs/template-search.md
|
|
@@ -77,6 +78,7 @@ files:
|
|
|
77
78
|
- lib/coolhand/open_ai/webhook_validator.rb
|
|
78
79
|
- lib/coolhand/optimization_feedback_link_service.rb
|
|
79
80
|
- lib/coolhand/pagination.rb
|
|
81
|
+
- lib/coolhand/public_content_service.rb
|
|
80
82
|
- lib/coolhand/rails_auto_declare.rb
|
|
81
83
|
- lib/coolhand/railtie.rb
|
|
82
84
|
- lib/coolhand/read_query.rb
|