ask-linear 0.1.0 → 0.1.1
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/lib/ask/linear/client.rb +7 -0
- data/lib/ask/linear/version.rb +1 -1
- data/lib/ask/skills/linear.use_linear/SKILL.md +162 -0
- metadata +16 -1
checksums.yaml
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
---
|
|
2
2
|
SHA256:
|
|
3
|
-
metadata.gz:
|
|
4
|
-
data.tar.gz:
|
|
3
|
+
metadata.gz: af9c693884b1bc9022c1cd4cdbe4c63d41329c382ece5b789bf845c8cec8dc87
|
|
4
|
+
data.tar.gz: 9d0d8ea95505b06494319ab80e5f43da5bc38b3372bc834bc6804a57c592b950
|
|
5
5
|
SHA512:
|
|
6
|
-
metadata.gz:
|
|
7
|
-
data.tar.gz:
|
|
6
|
+
metadata.gz: 07bc57b565a5d434a008b9446a59326896a1d0e721a9212fd84f8b26bb3bfcdbb9dc40626680428c27f14db557457658af6fbbc1643121b50098d2f44d12f274
|
|
7
|
+
data.tar.gz: c4e00fa504dbf5809db5e3d95d006b1e1373f71247b48d85229b7b52fc44a122be19e2ef3c2865904df1f62d744a9a1bd0b18cbf2b6000e52721d2ea97e1b469
|
data/lib/ask/linear/client.rb
CHANGED
|
@@ -1,6 +1,7 @@
|
|
|
1
1
|
# frozen_string_literal: true
|
|
2
2
|
|
|
3
3
|
require "faraday"
|
|
4
|
+
require "faraday/retry"
|
|
4
5
|
require "ask/auth"
|
|
5
6
|
|
|
6
7
|
module Ask
|
|
@@ -14,6 +15,7 @@ module Ask
|
|
|
14
15
|
# Configuration:
|
|
15
16
|
# - +read_timeout+: +30+ seconds
|
|
16
17
|
# - +open_timeout+: +10+ seconds
|
|
18
|
+
# - +retry+: up to 3 retries on 429 (rate-limit) and 5xx (server) errors
|
|
17
19
|
#
|
|
18
20
|
# @example
|
|
19
21
|
# client = Ask::Linear.client
|
|
@@ -43,6 +45,11 @@ module Ask
|
|
|
43
45
|
@api_key = api_key
|
|
44
46
|
@connection = Faraday.new(url: BASE_URL) do |f|
|
|
45
47
|
f.request :json
|
|
48
|
+
f.request :retry, max: 3,
|
|
49
|
+
interval: 1.0,
|
|
50
|
+
max_interval: 10.0,
|
|
51
|
+
backoff_factor: 2.0,
|
|
52
|
+
retry_statuses: [429, 500, 502, 503]
|
|
46
53
|
f.response :json
|
|
47
54
|
f.response :raise_error
|
|
48
55
|
f.options.read_timeout = 30
|
data/lib/ask/linear/version.rb
CHANGED
|
@@ -0,0 +1,162 @@
|
|
|
1
|
+
---
|
|
2
|
+
name: linear.use_linear
|
|
3
|
+
description: How to navigate the Linear API with GraphQL — explore the schema, build queries, paginate, and handle errors
|
|
4
|
+
---
|
|
5
|
+
|
|
6
|
+
Use this skill when you need to interact with Linear — managing issues, teams,
|
|
7
|
+
projects, sprints, or workflows. Unlike other service gems, Linear uses a raw
|
|
8
|
+
GraphQL API — there's no convenience client for each endpoint.
|
|
9
|
+
|
|
10
|
+
## Step 1: Get the Client
|
|
11
|
+
|
|
12
|
+
```ruby
|
|
13
|
+
client = Ask::Linear.client
|
|
14
|
+
```
|
|
15
|
+
|
|
16
|
+
This returns a `Faraday`-based client that sends HTTP POST to
|
|
17
|
+
`https://api.linear.app/graphql`. It expects a valid Linear API key resolved
|
|
18
|
+
via `Ask::Auth.resolve(:linear_api_key)`.
|
|
19
|
+
|
|
20
|
+
If you get an auth error, read `Ask::Linear::Context::AUTH_HOW` for API key setup.
|
|
21
|
+
|
|
22
|
+
## Step 2: Explore the Context
|
|
23
|
+
|
|
24
|
+
The gem ships with structured context you should reference:
|
|
25
|
+
|
|
26
|
+
```ruby
|
|
27
|
+
Ask::Linear::Context::DOCS_URL # Linear developer docs
|
|
28
|
+
Ask::Linear::Context::GRAPHQL_URL # GraphQL endpoint (for introspection)
|
|
29
|
+
Ask::Linear::Context::QUICK_START # Query/mutation examples
|
|
30
|
+
```
|
|
31
|
+
|
|
32
|
+
The `QUICK_START` constant has working examples for teams, issues, and mutations.
|
|
33
|
+
|
|
34
|
+
## Step 3: Use GraphQL Introspection to Discover the Schema
|
|
35
|
+
|
|
36
|
+
Since Linear is GraphQL, you can introspect the schema to discover types,
|
|
37
|
+
queries, and mutations:
|
|
38
|
+
|
|
39
|
+
```ruby
|
|
40
|
+
# List all query fields
|
|
41
|
+
result = client.query("
|
|
42
|
+
query {
|
|
43
|
+
__schema {
|
|
44
|
+
queryType {
|
|
45
|
+
fields {
|
|
46
|
+
name
|
|
47
|
+
description
|
|
48
|
+
}
|
|
49
|
+
}
|
|
50
|
+
}
|
|
51
|
+
}
|
|
52
|
+
")
|
|
53
|
+
```
|
|
54
|
+
|
|
55
|
+
For a specific type:
|
|
56
|
+
```ruby
|
|
57
|
+
result = client.query("
|
|
58
|
+
query {
|
|
59
|
+
__type(name: \"Issue\") {
|
|
60
|
+
name
|
|
61
|
+
fields {
|
|
62
|
+
name
|
|
63
|
+
type {
|
|
64
|
+
name
|
|
65
|
+
kind
|
|
66
|
+
}
|
|
67
|
+
}
|
|
68
|
+
}
|
|
69
|
+
}
|
|
70
|
+
")
|
|
71
|
+
```
|
|
72
|
+
|
|
73
|
+
For finding all mutations:
|
|
74
|
+
```ruby
|
|
75
|
+
result = client.query("
|
|
76
|
+
query {
|
|
77
|
+
__schema {
|
|
78
|
+
mutationType {
|
|
79
|
+
fields {
|
|
80
|
+
name
|
|
81
|
+
args { name type { name } }
|
|
82
|
+
}
|
|
83
|
+
}
|
|
84
|
+
}
|
|
85
|
+
}
|
|
86
|
+
")
|
|
87
|
+
```
|
|
88
|
+
|
|
89
|
+
## Step 4: Common Query Patterns
|
|
90
|
+
|
|
91
|
+
**List teams:**
|
|
92
|
+
```ruby
|
|
93
|
+
client.query("query { teams { nodes { id key name } } }")
|
|
94
|
+
```
|
|
95
|
+
|
|
96
|
+
**List issues for a team:**
|
|
97
|
+
```ruby
|
|
98
|
+
client.query("query { team(id: \"TEAM_ID\") { issues(first: 50) { nodes { id identifier title state { name } priority } } } }")
|
|
99
|
+
```
|
|
100
|
+
|
|
101
|
+
**Get issue details:**
|
|
102
|
+
```ruby
|
|
103
|
+
client.query("query($id: String!) { issue(id: $id) { id identifier title description url assignee { name } } }", { id: "ISSUE_ID" })
|
|
104
|
+
```
|
|
105
|
+
|
|
106
|
+
**Create an issue:**
|
|
107
|
+
```ruby
|
|
108
|
+
client.query("mutation($input: IssueCreateInput!) { issueCreate(input: $input) { success issue { id identifier title url } } }", { input: { teamId: "TEAM_ID", title: "New issue", description: "Description" } })
|
|
109
|
+
```
|
|
110
|
+
|
|
111
|
+
**Search issues:**
|
|
112
|
+
```ruby
|
|
113
|
+
client.query("query { issues(filter: { title: { contains: \"search term\" } }) { nodes { id identifier title } } }")
|
|
114
|
+
```
|
|
115
|
+
|
|
116
|
+
## Step 5: Variable Syntax
|
|
117
|
+
|
|
118
|
+
Linear's GraphQL API requires exact type names. Use introspection (`__type`)
|
|
119
|
+
to find available input types. Variables are passed as a hash:
|
|
120
|
+
|
|
121
|
+
```ruby
|
|
122
|
+
client.query("query($id: String!) { issue(id: $id) { id title } }", { id: "abc123" })
|
|
123
|
+
```
|
|
124
|
+
|
|
125
|
+
The second argument is variables — it's passed as the second parameter to
|
|
126
|
+
Faraday's `post`.
|
|
127
|
+
|
|
128
|
+
## Step 6: Authentication & Common Errors
|
|
129
|
+
|
|
130
|
+
For error guidance, use:
|
|
131
|
+
|
|
132
|
+
```ruby
|
|
133
|
+
Ask::Linear::Errors.for("AUTHENTICATION_ERROR")
|
|
134
|
+
Ask::Linear::Errors.status_code_description(429)
|
|
135
|
+
Ask::Linear::Errors::PAGINATION
|
|
136
|
+
```
|
|
137
|
+
|
|
138
|
+
Common scenarios:
|
|
139
|
+
- **401**: API key invalid or revoked → generate new key at Linear settings
|
|
140
|
+
- **429**: Rate limited (100 req/min per key) → wait and retry
|
|
141
|
+
- **GraphQL errors**: Query returns 200 with `errors` array → check field names
|
|
142
|
+
- **INPUT_VALIDATION_ERROR**: Wrong argument types → check schema for exact types
|
|
143
|
+
|
|
144
|
+
## Step 7: Pagination
|
|
145
|
+
|
|
146
|
+
Linear uses cursor-based connection pagination:
|
|
147
|
+
|
|
148
|
+
```ruby
|
|
149
|
+
# Get first page
|
|
150
|
+
page = client.query("query { issues(first: 50) { nodes { id title } pageInfo { hasNextPage endCursor } } }")
|
|
151
|
+
# Next page:
|
|
152
|
+
page = client.query("query($cursor: String) { issues(first: 50, after: $cursor) { nodes { id title } pageInfo { hasNextPage endCursor } } }", { cursor: page.data.issues.pageInfo.endCursor }) while page.data.issues.pageInfo.hasNextPage
|
|
153
|
+
```
|
|
154
|
+
|
|
155
|
+
Use `first`/`after` for forward pagination, `last`/`before` for backward.
|
|
156
|
+
|
|
157
|
+
## Step 8: Fallback Strategy
|
|
158
|
+
|
|
159
|
+
1. Check `Ask::Linear::Context::DOCS_URL` for documentation
|
|
160
|
+
2. Use GraphQL introspection to discover the schema
|
|
161
|
+
3. Linear's API returns helpful error messages — read the `errors` array
|
|
162
|
+
4. For complex queries, build them incrementally — start simple, add fields
|
metadata
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
|
2
2
|
name: ask-linear
|
|
3
3
|
version: !ruby/object:Gem::Version
|
|
4
|
-
version: 0.1.
|
|
4
|
+
version: 0.1.1
|
|
5
5
|
platform: ruby
|
|
6
6
|
authors:
|
|
7
7
|
- Kaka Ruto
|
|
@@ -37,6 +37,20 @@ dependencies:
|
|
|
37
37
|
- - "~>"
|
|
38
38
|
- !ruby/object:Gem::Version
|
|
39
39
|
version: '2.0'
|
|
40
|
+
- !ruby/object:Gem::Dependency
|
|
41
|
+
name: faraday-retry
|
|
42
|
+
requirement: !ruby/object:Gem::Requirement
|
|
43
|
+
requirements:
|
|
44
|
+
- - "~>"
|
|
45
|
+
- !ruby/object:Gem::Version
|
|
46
|
+
version: '2.0'
|
|
47
|
+
type: :runtime
|
|
48
|
+
prerelease: false
|
|
49
|
+
version_requirements: !ruby/object:Gem::Requirement
|
|
50
|
+
requirements:
|
|
51
|
+
- - "~>"
|
|
52
|
+
- !ruby/object:Gem::Version
|
|
53
|
+
version: '2.0'
|
|
40
54
|
- !ruby/object:Gem::Dependency
|
|
41
55
|
name: minitest
|
|
42
56
|
requirement: !ruby/object:Gem::Requirement
|
|
@@ -94,6 +108,7 @@ files:
|
|
|
94
108
|
- lib/ask/linear/context.rb
|
|
95
109
|
- lib/ask/linear/error_guide.rb
|
|
96
110
|
- lib/ask/linear/version.rb
|
|
111
|
+
- lib/ask/skills/linear.use_linear/SKILL.md
|
|
97
112
|
homepage: https://github.com/ask-rb/ask-linear
|
|
98
113
|
licenses:
|
|
99
114
|
- MIT
|