gitdog 0.0.0-stage → 0.1.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.
- package/README.md +76 -2
- package/dist/api-catalog.json +432 -0
- package/dist/api-keys.d.ts +15 -0
- package/dist/api-keys.js +93 -0
- package/dist/auth.d.ts +13 -0
- package/dist/auth.js +243 -0
- package/dist/catalog.d.ts +11 -0
- package/dist/catalog.js +8 -0
- package/dist/cli.d.ts +2 -0
- package/dist/cli.js +31 -0
- package/dist/client.d.ts +25 -0
- package/dist/client.js +109 -0
- package/dist/commands.d.ts +9 -0
- package/dist/commands.js +678 -0
- package/dist/projects.d.ts +55 -0
- package/dist/projects.js +349 -0
- package/dist/storage.d.ts +24 -0
- package/dist/storage.js +147 -0
- package/dist/ui.d.ts +17 -0
- package/dist/ui.js +155 -0
- package/package.json +54 -4
package/README.md
CHANGED
|
@@ -1,3 +1,77 @@
|
|
|
1
|
-
|
|
1
|
+
<p align="center">
|
|
2
|
+
<img src="https://raw.githubusercontent.com/hyodotdev/gitdog-cli/main/.github/assets/gitdog-logo.png" alt="Gitdog" width="112" height="112">
|
|
3
|
+
</p>
|
|
2
4
|
|
|
3
|
-
|
|
5
|
+
<h1 align="center">Gitdog CLI</h1>
|
|
6
|
+
|
|
7
|
+
<p align="center">
|
|
8
|
+
Your GitHub assistant. Now in the terminal.
|
|
9
|
+
</p>
|
|
10
|
+
|
|
11
|
+
<p align="center">
|
|
12
|
+
<a href="https://www.npmjs.com/package/gitdog"><img src="https://img.shields.io/npm/v/gitdog?logo=npm&color=CB3837" alt="npm version"></a>
|
|
13
|
+
<a href="https://www.npmjs.com/package/gitdog"><img src="https://img.shields.io/npm/dm/gitdog?color=555" alt="npm downloads"></a>
|
|
14
|
+
<a href="https://github.com/hyodotdev/gitdog-cli/actions/workflows/ci.yml"><img src="https://github.com/hyodotdev/gitdog-cli/actions/workflows/ci.yml/badge.svg?branch=main" alt="CI"></a>
|
|
15
|
+
<a href="https://nodejs.org"><img src="https://img.shields.io/badge/node-%3E%3D22.14.0-3c873a?logo=nodedotjs&logoColor=white" alt="Node.js 22.14 or later"></a>
|
|
16
|
+
<a href="https://gitdog.dev"><img src="https://img.shields.io/badge/Gitdog-gitdog.dev-111" alt="Gitdog website"></a>
|
|
17
|
+
</p>
|
|
18
|
+
|
|
19
|
+
<p align="center">
|
|
20
|
+
<img src="https://raw.githubusercontent.com/hyodotdev/gitdog-cli/main/.github/assets/terminal.svg" alt="Gitdog terminal: connect a project, configure automation and review pending actions" width="800">
|
|
21
|
+
</p>
|
|
22
|
+
|
|
23
|
+
Connect repositories, configure Gitdog's issue and discussion assistants, review
|
|
24
|
+
AI actions, and automate project tasks from your terminal or CI.
|
|
25
|
+
|
|
26
|
+
## Install
|
|
27
|
+
|
|
28
|
+
Requires **Node.js 22.14+**.
|
|
29
|
+
|
|
30
|
+
```sh
|
|
31
|
+
npm install --global gitdog
|
|
32
|
+
```
|
|
33
|
+
|
|
34
|
+
## Quick start
|
|
35
|
+
|
|
36
|
+
```sh
|
|
37
|
+
gitdog login
|
|
38
|
+
gitdog github install
|
|
39
|
+
gitdog github recover
|
|
40
|
+
gitdog init owner/repo
|
|
41
|
+
gitdog config set requireApproval true
|
|
42
|
+
gitdog config push
|
|
43
|
+
```
|
|
44
|
+
|
|
45
|
+
GitHub App setup is only needed once. A project connects an existing GitHub
|
|
46
|
+
repository to Gitdog.
|
|
47
|
+
|
|
48
|
+
## Everyday commands
|
|
49
|
+
|
|
50
|
+
| Task | Command |
|
|
51
|
+
| ------------------------ | ---------------------------- |
|
|
52
|
+
| List projects | `gitdog projects list` |
|
|
53
|
+
| Read automation settings | `gitdog config get --remote` |
|
|
54
|
+
| Review pending actions | `gitdog tickets pending` |
|
|
55
|
+
| Check code indexing | `gitdog index status` |
|
|
56
|
+
| List team members | `gitdog team members` |
|
|
57
|
+
| Check usage | `gitdog usage summary` |
|
|
58
|
+
|
|
59
|
+
Use `gitdog --help` to explore commands. Add `--json` for scripts.
|
|
60
|
+
|
|
61
|
+
## Use in CI
|
|
62
|
+
|
|
63
|
+
```sh
|
|
64
|
+
gitdog keys create --name ci
|
|
65
|
+
gitdog --key-file /path/to/key.json projects list --json
|
|
66
|
+
gitdog keys revoke KEY_ID --yes
|
|
67
|
+
```
|
|
68
|
+
|
|
69
|
+
`keys create` prints the private key file's path. Keys are project-scoped and
|
|
70
|
+
read-only by default; add `--write` for settings and ticket delete/restore. Keep key
|
|
71
|
+
files out of Git.
|
|
72
|
+
|
|
73
|
+
---
|
|
74
|
+
|
|
75
|
+
[Command reference](https://github.com/hyodotdev/gitdog-cli/blob/main/docs/REFERENCE.md)
|
|
76
|
+
· [Gitdog](https://gitdog.dev)
|
|
77
|
+
· [Report an issue](https://github.com/hyodotdev/gitdog-cli/issues)
|
|
@@ -0,0 +1,432 @@
|
|
|
1
|
+
[
|
|
2
|
+
{
|
|
3
|
+
"path": "admin/mutation:deleteAiLog",
|
|
4
|
+
"kind": "mutation",
|
|
5
|
+
"args": "{\n logId: v.id(\"aiLogs\"),\n }"
|
|
6
|
+
},
|
|
7
|
+
{
|
|
8
|
+
"path": "admin/mutation:updateAiLogStatus",
|
|
9
|
+
"kind": "mutation",
|
|
10
|
+
"args": "{\n logId: v.id(\"aiLogs\"),\n status: v.union(\n v.literal(\"success\"),\n v.literal(\"failed\"),\n v.literal(\"pending_approval\"),\n v.literal(\"approved\"),\n v.literal(\"rejected\"),\n v.literal(\"request_changes\"),\n ),\n userFeedback: v.optional(v.string()),\n }"
|
|
11
|
+
},
|
|
12
|
+
{
|
|
13
|
+
"path": "admin/paymentMutation:addTokens",
|
|
14
|
+
"kind": "mutation",
|
|
15
|
+
"args": "{\n subscriptionId: v.id(\"subscriptions\"),\n tokensToAdd: v.number(),\n operationId: v.string(),\n adminNote: v.optional(v.string()),\n }"
|
|
16
|
+
},
|
|
17
|
+
{
|
|
18
|
+
"path": "admin/paymentMutation:cancelSubscription",
|
|
19
|
+
"kind": "mutation",
|
|
20
|
+
"args": "{\n subscriptionId: v.id(\"subscriptions\"),\n operationId: v.string(),\n adminNote: v.optional(v.string()),\n }"
|
|
21
|
+
},
|
|
22
|
+
{
|
|
23
|
+
"path": "admin/paymentMutation:reactivateSubscription",
|
|
24
|
+
"kind": "mutation",
|
|
25
|
+
"args": "{\n subscriptionId: v.id(\"subscriptions\"),\n operationId: v.string(),\n adminNote: v.optional(v.string()),\n }"
|
|
26
|
+
},
|
|
27
|
+
{
|
|
28
|
+
"path": "admin/paymentMutation:reconcileGeminiChatUsage",
|
|
29
|
+
"kind": "mutation",
|
|
30
|
+
"args": "{\n reservationKey: v.string(),\n evidenceSource: v.union(\n v.literal(\"google_api_response\"),\n v.literal(\"google_cloud_billing_export\"),\n v.literal(\"google_support_confirmation\"),\n v.literal(\"anthropic_api_response\"),\n v.literal(\"anthropic_usage_report\"),\n v.literal(\"anthropic_support_confirmation\"),\n v.literal(\"openai_api_response\"),\n v.literal(\"openai_usage_report\"),\n v.literal(\"openai_support_confirmation\"),\n),\n evidenceReference: v.string(),\n outcome: v.union(\n v.object({ kind: v.literal(\"known_not_billed\") }),\n v.object({\n kind: v.literal(\"known_billed\"),\n actualInputTokens: v.number(),\n actualOutputTokens: v.number(),\n providerRequestId: v.optional(v.string()),\n }),\n ),\n }"
|
|
31
|
+
},
|
|
32
|
+
{
|
|
33
|
+
"path": "admin/paymentMutation:reconcileGeminiEmbeddingUsage",
|
|
34
|
+
"kind": "mutation",
|
|
35
|
+
"args": "{\n reservationKey: v.string(),\n evidenceSource: v.union(\n v.literal(\"google_api_response\"),\n v.literal(\"google_cloud_billing_export\"),\n v.literal(\"google_support_confirmation\"),\n v.literal(\"openai_api_response\"),\n v.literal(\"openai_billing_export\"),\n v.literal(\"openai_support_confirmation\"),\n),\n evidenceReference: v.string(),\n outcome: v.union(\n v.object({ kind: v.literal(\"known_not_billed\") }),\n v.object({\n kind: v.literal(\"known_billed\"),\n actualProviderTokens: v.number(),\n }),\n ),\n }"
|
|
36
|
+
},
|
|
37
|
+
{
|
|
38
|
+
"path": "admin/paymentMutation:refundTokens",
|
|
39
|
+
"kind": "mutation",
|
|
40
|
+
"args": "{\n subscriptionId: v.id(\"subscriptions\"),\n tokensToRefund: v.number(),\n adminNote: v.optional(v.string()),\n paymentLogId: v.id(\"paymentLogs\"),\n }"
|
|
41
|
+
},
|
|
42
|
+
{
|
|
43
|
+
"path": "admin/paymentMutation:requeueSubscriptionInvoiceReview",
|
|
44
|
+
"kind": "mutation",
|
|
45
|
+
"args": "{\n manualReviewId: v.id(\"paymentSettlementManualReviews\"),\n evidenceReference: v.string(),\n confirmRetry: v.literal(true),\n }"
|
|
46
|
+
},
|
|
47
|
+
{
|
|
48
|
+
"path": "admin/paymentMutation:updatePaymentLog",
|
|
49
|
+
"kind": "mutation",
|
|
50
|
+
"args": "{\n paymentLogId: v.id(\"paymentLogs\"),\n status: v.optional(\n v.union(\n v.literal(\"success\"),\n v.literal(\"failed\"),\n v.literal(\"pending\"),\n v.literal(\"refunded\"),\n v.literal(\"canceled\"),\n ),\n ),\n adminNote: v.optional(v.string()),\n }"
|
|
51
|
+
},
|
|
52
|
+
{
|
|
53
|
+
"path": "admin/paymentQuery:getPaymentStats",
|
|
54
|
+
"kind": "query",
|
|
55
|
+
"args": "{\n year: v.optional(v.number()),\n month: v.optional(v.number()), // 0-11 (January = 0)\n }"
|
|
56
|
+
},
|
|
57
|
+
{
|
|
58
|
+
"path": "admin/paymentQuery:listOpenSettlementReviews",
|
|
59
|
+
"kind": "query",
|
|
60
|
+
"args": "{ limit: v.optional(v.number()) }"
|
|
61
|
+
},
|
|
62
|
+
{
|
|
63
|
+
"path": "admin/paymentQuery:listPaymentLogs",
|
|
64
|
+
"kind": "query",
|
|
65
|
+
"args": "{\n limit: v.optional(v.number()),\n cursor: v.optional(v.string()),\n statusFilter: v.optional(\n v.union(\n v.literal(\"success\"),\n v.literal(\"failed\"),\n v.literal(\"pending\"),\n v.literal(\"refunded\"),\n v.literal(\"canceled\"),\n ),\n ),\n eventTypeFilter: v.optional(v.string()),\n }"
|
|
66
|
+
},
|
|
67
|
+
{
|
|
68
|
+
"path": "admin/paymentQuery:listPaymentLogsByUser",
|
|
69
|
+
"kind": "query",
|
|
70
|
+
"args": "{\n year: v.optional(v.number()),\n month: v.optional(v.number()), // 0-11 (January = 0)\n }"
|
|
71
|
+
},
|
|
72
|
+
{
|
|
73
|
+
"path": "admin/paymentQuery:listSubscriptions",
|
|
74
|
+
"kind": "query",
|
|
75
|
+
"args": "{\n limit: v.optional(v.number()),\n }"
|
|
76
|
+
},
|
|
77
|
+
{
|
|
78
|
+
"path": "admin/query:getAiLogById",
|
|
79
|
+
"kind": "query",
|
|
80
|
+
"args": "{\n logId: v.id(\"aiLogs\"),\n }"
|
|
81
|
+
},
|
|
82
|
+
{
|
|
83
|
+
"path": "admin/query:getAiLogStats",
|
|
84
|
+
"kind": "query",
|
|
85
|
+
"args": "{}"
|
|
86
|
+
},
|
|
87
|
+
{
|
|
88
|
+
"path": "admin/query:isAdmin",
|
|
89
|
+
"kind": "query",
|
|
90
|
+
"args": "{}"
|
|
91
|
+
},
|
|
92
|
+
{
|
|
93
|
+
"path": "admin/query:listAiLogs",
|
|
94
|
+
"kind": "query",
|
|
95
|
+
"args": "{\n status: v.optional(\n v.union(\n v.literal(\"success\"),\n v.literal(\"failed\"),\n v.literal(\"pending_approval\"),\n v.literal(\"approved\"),\n v.literal(\"rejected\"),\n v.literal(\"request_changes\"),\n ),\n ),\n workflowType: v.optional(v.string()),\n limit: v.optional(v.number()),\n cursor: v.optional(v.string()),\n }"
|
|
96
|
+
},
|
|
97
|
+
{
|
|
98
|
+
"path": "admin/query:listAiLogsByIndexing",
|
|
99
|
+
"kind": "query",
|
|
100
|
+
"args": "{\n limit: v.optional(v.number()),\n cursor: v.optional(v.number()),\n }"
|
|
101
|
+
},
|
|
102
|
+
{
|
|
103
|
+
"path": "admin/query:listAiLogsByTicket",
|
|
104
|
+
"kind": "query",
|
|
105
|
+
"args": "{\n limit: v.optional(v.number()),\n cursor: v.optional(v.number()), // createdAt timestamp for cursor-based pagination\n }"
|
|
106
|
+
},
|
|
107
|
+
{
|
|
108
|
+
"path": "apiKeys/action:create",
|
|
109
|
+
"kind": "action",
|
|
110
|
+
"args": "{\n repositoryId: v.id(\"repositories\"),\n name: v.string(),\n scopes: v.array(v.union(v.literal(\"read\"), v.literal(\"write\"))),\n expiresInDays: v.number(),\n }"
|
|
111
|
+
},
|
|
112
|
+
{
|
|
113
|
+
"path": "apiKeys/mutation:revoke",
|
|
114
|
+
"kind": "mutation",
|
|
115
|
+
"args": "{ keyId: v.id(\"projectApiKeys\") }"
|
|
116
|
+
},
|
|
117
|
+
{
|
|
118
|
+
"path": "apiKeys/query:list",
|
|
119
|
+
"kind": "query",
|
|
120
|
+
"args": "{\n repositoryId: v.id(\"repositories\"),\n paginationOpts: paginationOptsValidator,\n }"
|
|
121
|
+
},
|
|
122
|
+
{
|
|
123
|
+
"path": "github/action:listUserRepositories",
|
|
124
|
+
"kind": "action",
|
|
125
|
+
"args": "{\n cursor: v.optional(v.string()),\n reconnectRepositoryId: v.optional(v.string()),\n }"
|
|
126
|
+
},
|
|
127
|
+
{
|
|
128
|
+
"path": "github/action:recoverOAuthInstallation",
|
|
129
|
+
"kind": "action",
|
|
130
|
+
"args": "{}"
|
|
131
|
+
},
|
|
132
|
+
{
|
|
133
|
+
"path": "github/action:retryRepositoryAccessReconciliation",
|
|
134
|
+
"kind": "action",
|
|
135
|
+
"args": "{ installationId: v.number() }"
|
|
136
|
+
},
|
|
137
|
+
{
|
|
138
|
+
"path": "github/action:saveInstallation",
|
|
139
|
+
"kind": "action",
|
|
140
|
+
"args": "{\n installationId: v.number(),\n }"
|
|
141
|
+
},
|
|
142
|
+
{
|
|
143
|
+
"path": "github/query:getInstallation",
|
|
144
|
+
"kind": "query",
|
|
145
|
+
"args": "{\n installationId: v.number(),\n }"
|
|
146
|
+
},
|
|
147
|
+
{
|
|
148
|
+
"path": "github/query:getUserInstallation",
|
|
149
|
+
"kind": "query",
|
|
150
|
+
"args": "{}"
|
|
151
|
+
},
|
|
152
|
+
{
|
|
153
|
+
"path": "github/query:getUserInstallations",
|
|
154
|
+
"kind": "query",
|
|
155
|
+
"args": "{}"
|
|
156
|
+
},
|
|
157
|
+
{
|
|
158
|
+
"path": "invitations/action:create",
|
|
159
|
+
"kind": "action",
|
|
160
|
+
"args": "{\n repositoryId: v.id(\"repositories\"),\n inviteeGithubUsername: v.string(),\n role: v.literal(\"viewer\"),\n }"
|
|
161
|
+
},
|
|
162
|
+
{
|
|
163
|
+
"path": "invitations/mutation:accept",
|
|
164
|
+
"kind": "mutation",
|
|
165
|
+
"args": "{\n invitationId: v.id(\"invitations\"),\n }"
|
|
166
|
+
},
|
|
167
|
+
{
|
|
168
|
+
"path": "invitations/mutation:cancel",
|
|
169
|
+
"kind": "mutation",
|
|
170
|
+
"args": "{\n invitationId: v.id(\"invitations\"),\n }"
|
|
171
|
+
},
|
|
172
|
+
{
|
|
173
|
+
"path": "invitations/mutation:reject",
|
|
174
|
+
"kind": "mutation",
|
|
175
|
+
"args": "{\n invitationId: v.id(\"invitations\"),\n }"
|
|
176
|
+
},
|
|
177
|
+
{
|
|
178
|
+
"path": "invitations/query:getPendingForRepository",
|
|
179
|
+
"kind": "query",
|
|
180
|
+
"args": "{\n repositoryId: v.id(\"repositories\"),\n }"
|
|
181
|
+
},
|
|
182
|
+
{
|
|
183
|
+
"path": "invitations/query:listForRepository",
|
|
184
|
+
"kind": "query",
|
|
185
|
+
"args": "{\n repositoryId: v.id(\"repositories\"),\n }"
|
|
186
|
+
},
|
|
187
|
+
{
|
|
188
|
+
"path": "invitations/query:listPending",
|
|
189
|
+
"kind": "query",
|
|
190
|
+
"args": "{}"
|
|
191
|
+
},
|
|
192
|
+
{
|
|
193
|
+
"path": "notifications/mutation:markAllAsRead",
|
|
194
|
+
"kind": "mutation",
|
|
195
|
+
"args": "{}"
|
|
196
|
+
},
|
|
197
|
+
{
|
|
198
|
+
"path": "notifications/mutation:markAsRead",
|
|
199
|
+
"kind": "mutation",
|
|
200
|
+
"args": "{\n notificationId: v.id(\"notifications\"),\n }"
|
|
201
|
+
},
|
|
202
|
+
{
|
|
203
|
+
"path": "notifications/query:getUnreadCount",
|
|
204
|
+
"kind": "query",
|
|
205
|
+
"args": "{}"
|
|
206
|
+
},
|
|
207
|
+
{
|
|
208
|
+
"path": "notifications/query:list",
|
|
209
|
+
"kind": "query",
|
|
210
|
+
"args": "{\n limit: v.optional(v.number()),\n }"
|
|
211
|
+
},
|
|
212
|
+
{
|
|
213
|
+
"path": "notifications/query:listUnread",
|
|
214
|
+
"kind": "query",
|
|
215
|
+
"args": "{}"
|
|
216
|
+
},
|
|
217
|
+
{
|
|
218
|
+
"path": "repoIndexing/mutation:initializeIndexing",
|
|
219
|
+
"kind": "mutation",
|
|
220
|
+
"args": "{\n repositoryId: v.id(\"repositories\"),\n }"
|
|
221
|
+
},
|
|
222
|
+
{
|
|
223
|
+
"path": "repoIndexing/query:getFileContent",
|
|
224
|
+
"kind": "query",
|
|
225
|
+
"args": "{\n repositoryId: v.id(\"repositories\"),\n filePath: v.string(),\n }"
|
|
226
|
+
},
|
|
227
|
+
{
|
|
228
|
+
"path": "repoIndexing/query:getFileList",
|
|
229
|
+
"kind": "query",
|
|
230
|
+
"args": "{\n repositoryId: v.id(\"repositories\"),\n limit: v.optional(v.number()),\n }"
|
|
231
|
+
},
|
|
232
|
+
{
|
|
233
|
+
"path": "repoIndexing/query:getIndexingLogs",
|
|
234
|
+
"kind": "query",
|
|
235
|
+
"args": "{\n repositoryId: v.id(\"repositories\"),\n limit: v.optional(v.number()),\n }"
|
|
236
|
+
},
|
|
237
|
+
{
|
|
238
|
+
"path": "repoIndexing/query:getIndexingStatus",
|
|
239
|
+
"kind": "query",
|
|
240
|
+
"args": "{\n repositoryId: v.id(\"repositories\"),\n }"
|
|
241
|
+
},
|
|
242
|
+
{
|
|
243
|
+
"path": "repoLearnings/query:countByRepository",
|
|
244
|
+
"kind": "query",
|
|
245
|
+
"args": "{\n repositoryId: v.id(\"repositories\"),\n }"
|
|
246
|
+
},
|
|
247
|
+
{
|
|
248
|
+
"path": "repositories/action:createAndIndex",
|
|
249
|
+
"kind": "action",
|
|
250
|
+
"args": "{\n installationId: v.number(),\n githubRepositoryId: v.number(),\n reconnectRepositoryId: v.optional(v.string()),\n }"
|
|
251
|
+
},
|
|
252
|
+
{
|
|
253
|
+
"path": "repositories/action:syncRepository",
|
|
254
|
+
"kind": "action",
|
|
255
|
+
"args": "{\n repositoryId: v.id(\"repositories\"),\n }"
|
|
256
|
+
},
|
|
257
|
+
{
|
|
258
|
+
"path": "repositories/mutation:remove",
|
|
259
|
+
"kind": "mutation",
|
|
260
|
+
"args": "{ repositoryId: v.id(\"repositories\") }"
|
|
261
|
+
},
|
|
262
|
+
{
|
|
263
|
+
"path": "repositories/mutation:toggleActive",
|
|
264
|
+
"kind": "mutation",
|
|
265
|
+
"args": "{\n repositoryId: v.id(\"repositories\"),\n isActive: v.optional(v.boolean()),\n }"
|
|
266
|
+
},
|
|
267
|
+
{
|
|
268
|
+
"path": "repositories/mutation:updateSettings",
|
|
269
|
+
"kind": "mutation",
|
|
270
|
+
"args": "{\n repositoryId: v.id(\"repositories\"),\n settings: v.object({\n issueAssistantEnabled: v.boolean(),\n autoFormatIssue: v.boolean(),\n autoAnswerQuestions: v.boolean(),\n tagMaintainersForCodeChanges: v.boolean(),\n issueResponseStyle: v.optional(v.string()),\n requireApproval: v.boolean(),\n discussionAssistantEnabled: v.boolean(),\n autoFormatDiscussion: v.boolean(),\n autoAnswerDiscussionQuestions: v.boolean(),\n tagMaintainersForDiscussionCodeChanges: v.boolean(),\n discussionResponseStyle: v.optional(v.string()),\n requireApprovalForDiscussions: v.boolean(),\n }),\n }"
|
|
271
|
+
},
|
|
272
|
+
{
|
|
273
|
+
"path": "repositories/query:get",
|
|
274
|
+
"kind": "query",
|
|
275
|
+
"args": "{\n owner: v.string(),\n repo: v.string(),\n }"
|
|
276
|
+
},
|
|
277
|
+
{
|
|
278
|
+
"path": "repositories/query:getById",
|
|
279
|
+
"kind": "query",
|
|
280
|
+
"args": "{\n repositoryId: v.id(\"repositories\"),\n }"
|
|
281
|
+
},
|
|
282
|
+
{
|
|
283
|
+
"path": "repositories/query:getConnectedRepos",
|
|
284
|
+
"kind": "query",
|
|
285
|
+
"args": "{}"
|
|
286
|
+
},
|
|
287
|
+
{
|
|
288
|
+
"path": "repositories/query:getReconnectTarget",
|
|
289
|
+
"kind": "query",
|
|
290
|
+
"args": "{\n reconnectRepositoryId: v.string(),\n }"
|
|
291
|
+
},
|
|
292
|
+
{
|
|
293
|
+
"path": "repositories/query:list",
|
|
294
|
+
"kind": "query",
|
|
295
|
+
"args": "{}"
|
|
296
|
+
},
|
|
297
|
+
{
|
|
298
|
+
"path": "repositoryMembers/mutation:leave",
|
|
299
|
+
"kind": "mutation",
|
|
300
|
+
"args": "{\n repositoryId: v.id(\"repositories\"),\n }"
|
|
301
|
+
},
|
|
302
|
+
{
|
|
303
|
+
"path": "repositoryMembers/mutation:remove",
|
|
304
|
+
"kind": "mutation",
|
|
305
|
+
"args": "{\n memberId: v.id(\"repositoryMembers\"),\n }"
|
|
306
|
+
},
|
|
307
|
+
{
|
|
308
|
+
"path": "repositoryMembers/query:getMyRole",
|
|
309
|
+
"kind": "query",
|
|
310
|
+
"args": "{\n repositoryId: v.id(\"repositories\"),\n }"
|
|
311
|
+
},
|
|
312
|
+
{
|
|
313
|
+
"path": "repositoryMembers/query:list",
|
|
314
|
+
"kind": "query",
|
|
315
|
+
"args": "{\n repositoryId: v.id(\"repositories\"),\n }"
|
|
316
|
+
},
|
|
317
|
+
{
|
|
318
|
+
"path": "subscriptions/action:createCheckoutUrl",
|
|
319
|
+
"kind": "action",
|
|
320
|
+
"args": "{\n plan: v.literal(\"pro\"),\n }"
|
|
321
|
+
},
|
|
322
|
+
{
|
|
323
|
+
"path": "subscriptions/action:createTokenPackCheckoutUrl",
|
|
324
|
+
"kind": "action",
|
|
325
|
+
"args": "{\n packSize: v.union(v.literal(\"small\"), v.literal(\"large\")),\n }"
|
|
326
|
+
},
|
|
327
|
+
{
|
|
328
|
+
"path": "subscriptions/query:calculateOverage",
|
|
329
|
+
"kind": "query",
|
|
330
|
+
"args": "{}"
|
|
331
|
+
},
|
|
332
|
+
{
|
|
333
|
+
"path": "subscriptions/query:canPerformAction",
|
|
334
|
+
"kind": "query",
|
|
335
|
+
"args": "{}"
|
|
336
|
+
},
|
|
337
|
+
{
|
|
338
|
+
"path": "subscriptions/query:getCurrent",
|
|
339
|
+
"kind": "query",
|
|
340
|
+
"args": "{}"
|
|
341
|
+
},
|
|
342
|
+
{
|
|
343
|
+
"path": "subscriptions/query:getPricingInfo",
|
|
344
|
+
"kind": "query",
|
|
345
|
+
"args": "{}"
|
|
346
|
+
},
|
|
347
|
+
{
|
|
348
|
+
"path": "ticketActions/action:approve",
|
|
349
|
+
"kind": "action",
|
|
350
|
+
"args": "{\n actionId: v.id(\"ticketActions\"),\n }"
|
|
351
|
+
},
|
|
352
|
+
{
|
|
353
|
+
"path": "ticketActions/action:reject",
|
|
354
|
+
"kind": "action",
|
|
355
|
+
"args": "{\n actionId: v.id(\"ticketActions\"),\n }"
|
|
356
|
+
},
|
|
357
|
+
{
|
|
358
|
+
"path": "ticketActions/action:requestChanges",
|
|
359
|
+
"kind": "action",
|
|
360
|
+
"args": "{\n actionId: v.id(\"ticketActions\"),\n feedback: v.string(),\n }"
|
|
361
|
+
},
|
|
362
|
+
{
|
|
363
|
+
"path": "ticketActions/query:getById",
|
|
364
|
+
"kind": "query",
|
|
365
|
+
"args": "{\n id: v.id(\"ticketActions\"),\n }"
|
|
366
|
+
},
|
|
367
|
+
{
|
|
368
|
+
"path": "ticketActions/query:listByTicket",
|
|
369
|
+
"kind": "query",
|
|
370
|
+
"args": "{\n ticketId: v.id(\"tickets\"),\n }"
|
|
371
|
+
},
|
|
372
|
+
{
|
|
373
|
+
"path": "tickets/mutation:restore",
|
|
374
|
+
"kind": "mutation",
|
|
375
|
+
"args": "{\n id: v.id(\"tickets\"),\n }"
|
|
376
|
+
},
|
|
377
|
+
{
|
|
378
|
+
"path": "tickets/mutation:softDelete",
|
|
379
|
+
"kind": "mutation",
|
|
380
|
+
"args": "{\n id: v.id(\"tickets\"),\n }"
|
|
381
|
+
},
|
|
382
|
+
{
|
|
383
|
+
"path": "tickets/query:getById",
|
|
384
|
+
"kind": "query",
|
|
385
|
+
"args": "{\n id: v.id(\"tickets\"),\n }"
|
|
386
|
+
},
|
|
387
|
+
{
|
|
388
|
+
"path": "tickets/query:list",
|
|
389
|
+
"kind": "query",
|
|
390
|
+
"args": "{\n githubRepo: v.optional(v.string()),\n status: v.optional(v.union(v.literal(\"open\"), v.literal(\"closed\"))),\n ticketType: v.optional(\n v.union(v.literal(\"issue\"), v.literal(\"discussion\")),\n ),\n search: v.optional(v.string()),\n limit: v.optional(v.number()),\n offset: v.optional(v.number()),\n }"
|
|
391
|
+
},
|
|
392
|
+
{
|
|
393
|
+
"path": "tickets/query:listPendingApproval",
|
|
394
|
+
"kind": "query",
|
|
395
|
+
"args": "{\n githubRepo: v.optional(v.string()),\n ticketType: v.optional(\n v.union(v.literal(\"issue\"), v.literal(\"discussion\")),\n ),\n search: v.optional(v.string()),\n limit: v.optional(v.number()),\n offset: v.optional(v.number()),\n }"
|
|
396
|
+
},
|
|
397
|
+
{
|
|
398
|
+
"path": "tokenUsage/query:getCurrentMonthUsage",
|
|
399
|
+
"kind": "query",
|
|
400
|
+
"args": "{}"
|
|
401
|
+
},
|
|
402
|
+
{
|
|
403
|
+
"path": "tokenUsage/query:getUsageByRepository",
|
|
404
|
+
"kind": "query",
|
|
405
|
+
"args": "{}"
|
|
406
|
+
},
|
|
407
|
+
{
|
|
408
|
+
"path": "users/action:ensureProfile",
|
|
409
|
+
"kind": "action",
|
|
410
|
+
"args": "{}"
|
|
411
|
+
},
|
|
412
|
+
{
|
|
413
|
+
"path": "users/mutation:attestLegalEligibility",
|
|
414
|
+
"kind": "mutation",
|
|
415
|
+
"args": "{\n minimumAgeConfirmed: v.literal(true),\n professionalUseConfirmed: v.literal(true),\n termsAccepted: v.literal(true),\n privacyPolicyAccepted: v.literal(true),\n displayedTermsVersion: v.string(),\n displayedPrivacyPolicyVersion: v.string(),\n }"
|
|
416
|
+
},
|
|
417
|
+
{
|
|
418
|
+
"path": "users/mutation:ensureProfileFromAuth",
|
|
419
|
+
"kind": "mutation",
|
|
420
|
+
"args": "{}"
|
|
421
|
+
},
|
|
422
|
+
{
|
|
423
|
+
"path": "users/query:getCurrentUser",
|
|
424
|
+
"kind": "query",
|
|
425
|
+
"args": "{}"
|
|
426
|
+
},
|
|
427
|
+
{
|
|
428
|
+
"path": "users/query:getProfile",
|
|
429
|
+
"kind": "query",
|
|
430
|
+
"args": "{ userId: v.id(\"users\") }"
|
|
431
|
+
}
|
|
432
|
+
]
|
|
@@ -0,0 +1,15 @@
|
|
|
1
|
+
export type ProjectKey = {
|
|
2
|
+
version: 1;
|
|
3
|
+
apiKey: string;
|
|
4
|
+
apiUrl: string;
|
|
5
|
+
httpUrl: string;
|
|
6
|
+
keyId: string;
|
|
7
|
+
repositoryId: string;
|
|
8
|
+
name: string;
|
|
9
|
+
scopes: string[];
|
|
10
|
+
expiresAt: number;
|
|
11
|
+
};
|
|
12
|
+
export declare function projectHttpUrl(apiUrl: string): string;
|
|
13
|
+
export declare function readProjectKey(path: string): Promise<ProjectKey>;
|
|
14
|
+
export declare function saveProjectKey(path: string, key: ProjectKey): Promise<void>;
|
|
15
|
+
export declare function callWithProjectKey<T>(apiUrl: string, keyFile: string | undefined, rawKey: string | undefined, kind: string, path: string, args: unknown, timeoutMs: number): Promise<T>;
|
package/dist/api-keys.js
ADDED
|
@@ -0,0 +1,93 @@
|
|
|
1
|
+
import { mkdir, open, readFile, rm } from "node:fs/promises";
|
|
2
|
+
import { dirname, resolve } from "node:path";
|
|
3
|
+
import { asRecord } from "./ui.js";
|
|
4
|
+
import { validateUrl } from "./storage.js";
|
|
5
|
+
export function projectHttpUrl(apiUrl) {
|
|
6
|
+
return validateUrl(process.env.GITDOG_HTTP_URL ??
|
|
7
|
+
apiUrl.replace(/\.convex\.cloud$/, ".convex.site"), "Project HTTP URL");
|
|
8
|
+
}
|
|
9
|
+
export async function readProjectKey(path) {
|
|
10
|
+
let value;
|
|
11
|
+
try {
|
|
12
|
+
value = JSON.parse(await readFile(resolve(path), "utf8"));
|
|
13
|
+
}
|
|
14
|
+
catch {
|
|
15
|
+
throw new Error("Cannot read the API key file. Check its path, permissions and JSON syntax.");
|
|
16
|
+
}
|
|
17
|
+
const key = asRecord(value);
|
|
18
|
+
if (key?.version !== 1 ||
|
|
19
|
+
typeof key.apiKey !== "string" ||
|
|
20
|
+
!/^gdk_[a-f0-9]{64}$/.test(key.apiKey) ||
|
|
21
|
+
typeof key.apiUrl !== "string" ||
|
|
22
|
+
typeof key.httpUrl !== "string" ||
|
|
23
|
+
typeof key.keyId !== "string" ||
|
|
24
|
+
typeof key.repositoryId !== "string" ||
|
|
25
|
+
typeof key.name !== "string" ||
|
|
26
|
+
!Array.isArray(key.scopes) ||
|
|
27
|
+
!key.scopes.every((scope) => typeof scope === "string") ||
|
|
28
|
+
typeof key.expiresAt !== "number")
|
|
29
|
+
throw new Error("Invalid Gitdog project API key file.");
|
|
30
|
+
return {
|
|
31
|
+
version: 1,
|
|
32
|
+
apiKey: key.apiKey,
|
|
33
|
+
apiUrl: validateUrl(key.apiUrl, "Key API URL"),
|
|
34
|
+
httpUrl: validateUrl(key.httpUrl, "Key HTTP URL"),
|
|
35
|
+
keyId: key.keyId,
|
|
36
|
+
repositoryId: key.repositoryId,
|
|
37
|
+
name: key.name,
|
|
38
|
+
scopes: key.scopes,
|
|
39
|
+
expiresAt: key.expiresAt,
|
|
40
|
+
};
|
|
41
|
+
}
|
|
42
|
+
export async function saveProjectKey(path, key) {
|
|
43
|
+
await mkdir(dirname(path), { recursive: true, mode: 0o700 });
|
|
44
|
+
const handle = await open(path, "wx", 0o600);
|
|
45
|
+
try {
|
|
46
|
+
await handle.writeFile(JSON.stringify(key, null, 2) + "\n");
|
|
47
|
+
}
|
|
48
|
+
catch (error) {
|
|
49
|
+
await handle.close();
|
|
50
|
+
await rm(path, { force: true });
|
|
51
|
+
throw error;
|
|
52
|
+
}
|
|
53
|
+
await handle.close();
|
|
54
|
+
}
|
|
55
|
+
export async function callWithProjectKey(apiUrl, keyFile, rawKey, kind, path, args, timeoutMs) {
|
|
56
|
+
const deadline = Date.now() + timeoutMs;
|
|
57
|
+
if (rawKey && keyFile)
|
|
58
|
+
throw new Error("Select GITDOG_API_KEY or a key file, not both.");
|
|
59
|
+
const credential = keyFile ? await readProjectKey(keyFile) : undefined;
|
|
60
|
+
if (credential && credential.apiUrl !== apiUrl)
|
|
61
|
+
throw new Error("This API key file belongs to another API URL. Select the matching --api-url.");
|
|
62
|
+
const key = credential?.apiKey ?? rawKey;
|
|
63
|
+
if (!key || !/^gdk_[a-f0-9]{64}$/.test(key))
|
|
64
|
+
throw new Error("Invalid Gitdog project API key.");
|
|
65
|
+
if (kind === "action")
|
|
66
|
+
throw new Error("This command requires an owner login. Project API keys cannot manage accounts, keys, billing or GitHub actions.");
|
|
67
|
+
const remaining = deadline - Date.now();
|
|
68
|
+
if (remaining <= 0)
|
|
69
|
+
throw new Error("Project API request timed out.");
|
|
70
|
+
const response = await fetch(`${credential?.httpUrl ?? projectHttpUrl(apiUrl)}/v1/cli`, {
|
|
71
|
+
method: "POST",
|
|
72
|
+
redirect: "error",
|
|
73
|
+
signal: AbortSignal.timeout(remaining),
|
|
74
|
+
headers: { "Content-Type": "application/json", "X-Gitdog-Api-Key": key },
|
|
75
|
+
body: JSON.stringify({ kind, path, args }),
|
|
76
|
+
});
|
|
77
|
+
let result;
|
|
78
|
+
try {
|
|
79
|
+
result = asRecord(await response.json());
|
|
80
|
+
}
|
|
81
|
+
catch {
|
|
82
|
+
throw new Error(`Project API returned HTTP ${response.status} without a JSON response.`);
|
|
83
|
+
}
|
|
84
|
+
if (!response.ok) {
|
|
85
|
+
const error = asRecord(result?.error);
|
|
86
|
+
throw new Error(typeof error?.message === "string"
|
|
87
|
+
? error.message
|
|
88
|
+
: `Project API returned HTTP ${response.status}.`);
|
|
89
|
+
}
|
|
90
|
+
if (!result || !Object.hasOwn(result, "value"))
|
|
91
|
+
throw new Error("Invalid project API response.");
|
|
92
|
+
return result.value;
|
|
93
|
+
}
|
package/dist/auth.d.ts
ADDED
|
@@ -0,0 +1,13 @@
|
|
|
1
|
+
import { SessionStore } from "./storage.js";
|
|
2
|
+
import { type Ui } from "./ui.js";
|
|
3
|
+
export declare const CALLBACK_PATH = "/gitdog/callback";
|
|
4
|
+
export declare function openBrowser(url: string, signal?: AbortSignal): Promise<boolean>;
|
|
5
|
+
export declare function createLoginListener(timeoutMs?: number): Promise<{
|
|
6
|
+
redirectTo: string;
|
|
7
|
+
signal: AbortSignal;
|
|
8
|
+
code: Promise<string>;
|
|
9
|
+
close: () => Promise<void>;
|
|
10
|
+
}>;
|
|
11
|
+
export declare function validateAuthRedirect(value: string, apiUrl: string): void;
|
|
12
|
+
export declare function login(apiUrl: string, siteUrl: string, ui: Ui, noBrowser?: boolean): Promise<void>;
|
|
13
|
+
export declare function logout(ui: Ui, localOnly?: boolean, store?: SessionStore): Promise<void>;
|