latchkey 0.2.0 → 1.0.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.
- package/README.md +98 -57
- package/dist/integrations/SKILL.md +25 -19
- package/dist/package.json +2 -2
- package/dist/scripts/codegen/codeGenerator.d.ts +27 -0
- package/dist/scripts/codegen/codeGenerator.d.ts.map +1 -0
- package/dist/scripts/codegen/codeGenerator.js +220 -0
- package/dist/scripts/codegen/codeGenerator.js.map +1 -0
- package/dist/scripts/codegen/index.d.ts +27 -0
- package/dist/scripts/codegen/index.d.ts.map +1 -0
- package/dist/scripts/codegen/index.js +189 -0
- package/dist/scripts/codegen/index.js.map +1 -0
- package/dist/scripts/codegen/injectedScript.d.ts +6 -0
- package/dist/scripts/codegen/injectedScript.d.ts.map +1 -0
- package/dist/scripts/codegen/injectedScript.js +657 -0
- package/dist/scripts/codegen/injectedScript.js.map +1 -0
- package/dist/scripts/codegen/requestMetadataCollector.d.ts +15 -0
- package/dist/scripts/codegen/requestMetadataCollector.d.ts.map +1 -0
- package/dist/scripts/codegen/requestMetadataCollector.js +48 -0
- package/dist/scripts/codegen/requestMetadataCollector.js.map +1 -0
- package/dist/scripts/codegen/types.d.ts +77 -0
- package/dist/scripts/codegen/types.d.ts.map +1 -0
- package/dist/scripts/codegen/types.js +10 -0
- package/dist/scripts/codegen/types.js.map +1 -0
- package/dist/scripts/codegen.d.ts +24 -0
- package/dist/scripts/codegen.d.ts.map +1 -0
- package/dist/scripts/codegen.js +95 -0
- package/dist/scripts/codegen.js.map +1 -0
- package/dist/scripts/cryptFile.js +7 -2
- package/dist/scripts/cryptFile.js.map +1 -1
- package/dist/src/apiCredentialStore.d.ts +1 -0
- package/dist/src/apiCredentialStore.d.ts.map +1 -1
- package/dist/src/apiCredentialStore.js +12 -0
- package/dist/src/apiCredentialStore.js.map +1 -1
- package/dist/src/apiCredentials.d.ts +33 -0
- package/dist/src/apiCredentials.d.ts.map +1 -1
- package/dist/src/apiCredentials.js +36 -0
- package/dist/src/apiCredentials.js.map +1 -1
- package/dist/src/cli.js +3 -2
- package/dist/src/cli.js.map +1 -1
- package/dist/src/cliCommands.d.ts.map +1 -1
- package/dist/src/cliCommands.js +158 -126
- package/dist/src/cliCommands.js.map +1 -1
- package/dist/src/config.d.ts +13 -0
- package/dist/src/config.d.ts.map +1 -1
- package/dist/src/config.js +56 -16
- package/dist/src/config.js.map +1 -1
- package/dist/src/encryptedStorage.d.ts +1 -2
- package/dist/src/encryptedStorage.d.ts.map +1 -1
- package/dist/src/encryptedStorage.js +18 -38
- package/dist/src/encryptedStorage.js.map +1 -1
- package/dist/src/index.d.ts +2 -2
- package/dist/src/index.d.ts.map +1 -1
- package/dist/src/index.js +3 -3
- package/dist/src/index.js.map +1 -1
- package/dist/src/keychain.d.ts +0 -4
- package/dist/src/keychain.d.ts.map +1 -1
- package/dist/src/keychain.js +0 -13
- package/dist/src/keychain.js.map +1 -1
- package/dist/src/oauthUtils.d.ts +1 -1
- package/dist/src/oauthUtils.d.ts.map +1 -1
- package/dist/src/playwrightUtils.d.ts +6 -0
- package/dist/src/playwrightUtils.d.ts.map +1 -1
- package/dist/src/playwrightUtils.js +12 -0
- package/dist/src/playwrightUtils.js.map +1 -1
- package/dist/src/registry.d.ts.map +1 -1
- package/dist/src/registry.js +20 -4
- package/dist/src/registry.js.map +1 -1
- package/dist/src/services/base.d.ts +20 -18
- package/dist/src/services/base.d.ts.map +1 -1
- package/dist/src/services/base.js +37 -1
- package/dist/src/services/base.js.map +1 -1
- package/dist/src/services/discord.d.ts +2 -3
- package/dist/src/services/discord.d.ts.map +1 -1
- package/dist/src/services/discord.js +3 -22
- package/dist/src/services/discord.js.map +1 -1
- package/dist/src/services/dropbox.d.ts +2 -3
- package/dist/src/services/dropbox.d.ts.map +1 -1
- package/dist/src/services/dropbox.js +3 -22
- package/dist/src/services/dropbox.js.map +1 -1
- package/dist/src/services/github.d.ts +2 -3
- package/dist/src/services/github.d.ts.map +1 -1
- package/dist/src/services/github.js +3 -22
- package/dist/src/services/github.js.map +1 -1
- package/dist/src/services/google.d.ts +3 -4
- package/dist/src/services/google.d.ts.map +1 -1
- package/dist/src/services/google.js +21 -43
- package/dist/src/services/google.js.map +1 -1
- package/dist/src/services/index.d.ts +2 -2
- package/dist/src/services/index.d.ts.map +1 -1
- package/dist/src/services/index.js +2 -1
- package/dist/src/services/index.js.map +1 -1
- package/dist/src/services/linear.d.ts +2 -3
- package/dist/src/services/linear.d.ts.map +1 -1
- package/dist/src/services/linear.js +3 -23
- package/dist/src/services/linear.js.map +1 -1
- package/dist/src/services/mailchimp.d.ts +11 -0
- package/dist/src/services/mailchimp.d.ts.map +1 -0
- package/dist/src/services/mailchimp.js +16 -0
- package/dist/src/services/mailchimp.js.map +1 -0
- package/dist/src/services/notion.d.ts +2 -3
- package/dist/src/services/notion.d.ts.map +1 -1
- package/dist/src/services/notion.js +3 -22
- package/dist/src/services/notion.js.map +1 -1
- package/dist/src/services/slack.d.ts +1 -1
- package/dist/src/services/slack.d.ts.map +1 -1
- package/dist/src/services/slack.js +2 -5
- package/dist/src/services/slack.js.map +1 -1
- package/dist/tests/apiCredentials.test.js +59 -1
- package/dist/tests/apiCredentials.test.js.map +1 -1
- package/dist/tests/cli.test.js +270 -128
- package/dist/tests/cli.test.js.map +1 -1
- package/dist/tests/playwrightDownload.test.js +2 -2
- package/dist/tests/playwrightDownload.test.js.map +1 -1
- package/dist/tests/registry.test.js +14 -2
- package/dist/tests/registry.test.js.map +1 -1
- package/dist/tests/servicesAgainstRecordings.test.js +3 -0
- package/dist/tests/servicesAgainstRecordings.test.js.map +1 -1
- package/package.json +2 -2
package/README.md
CHANGED
|
@@ -1,10 +1,14 @@
|
|
|
1
1
|
# Latchkey
|
|
2
2
|
|
|
3
|
-
|
|
3
|
+
Inject API credentials into local agent requests.
|
|
4
4
|
|
|
5
5
|
## Quick example
|
|
6
6
|
|
|
7
7
|
```
|
|
8
|
+
# User stores the credentials.
|
|
9
|
+
latchkey auth set slack -H "Authorization: Bearer xoxb-your-token"
|
|
10
|
+
|
|
11
|
+
# Agent makes http calls.
|
|
8
12
|
latchkey curl -X POST 'https://slack.com/api/conversations.create' \
|
|
9
13
|
-H 'Content-Type: application/json' \
|
|
10
14
|
-d '{"name":"something-urgent"}'
|
|
@@ -12,52 +16,64 @@ latchkey curl -X POST 'https://slack.com/api/conversations.create' \
|
|
|
12
16
|
|
|
13
17
|
## Overview
|
|
14
18
|
|
|
15
|
-
Latchkey is a command-line tool that injects credentials
|
|
19
|
+
Latchkey is a command-line tool that injects credentials into curl
|
|
20
|
+
requests to known public APIs.
|
|
16
21
|
|
|
17
|
-
- `latchkey services`
|
|
18
|
-
-
|
|
22
|
+
- `latchkey services list`
|
|
23
|
+
- List supported third-party services (Slack, Google Workspace, Linear, GitHub, etc.).
|
|
19
24
|
- `latchkey curl <arguments>`
|
|
20
25
|
- Automatically inject credentials to your otherwise standard curl calls to public APIs.
|
|
21
|
-
-
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
credentials
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
|
|
26
|
+
- Credentials must already exist (see below).
|
|
27
|
+
- `latchkey auth set <service_name> <curl_arguments>`
|
|
28
|
+
- Manually store credentials for a service as arbitrary curl arguments.
|
|
29
|
+
- `latchkey auth browser <service_name>`
|
|
30
|
+
- Open a browser login pop-up window and store the resulting API credentials.
|
|
31
|
+
- This also allows agents to prompt users for credentials.
|
|
32
|
+
- Only some services support this option.
|
|
33
|
+
|
|
34
|
+
Latchkey is primarily designed for AI agents. By invoking
|
|
35
|
+
Latchkey, agents can prompt the user to authenticate when needed,
|
|
36
|
+
then continue interacting with third-party APIs using standard
|
|
37
|
+
curl syntax - no custom integrations or embedded credentials
|
|
38
|
+
required.
|
|
39
|
+
|
|
40
|
+
Unlike OAuth-based flows or typical MCP-style integrations,
|
|
41
|
+
Latchkey does not introduce an intermediary between the agent
|
|
42
|
+
and the service. When `browser` is used, requests are made
|
|
43
|
+
directly on the user’s behalf, which enables greater flexibility
|
|
44
|
+
at the cost of formal delegation: agents authenticate as the
|
|
45
|
+
user.
|
|
46
|
+
|
|
47
|
+
If a service you need isn’t supported yet, contributions are welcome!
|
|
48
|
+
See the [development docs](docs/development.md) for details.
|
|
37
49
|
|
|
38
50
|
## Installation
|
|
39
51
|
|
|
40
52
|
### Prerequisites
|
|
41
53
|
|
|
42
54
|
- `curl`, `node` and `npm` need to be present on your system in reasonably recent versions.
|
|
43
|
-
- The browser requires a graphical environment.
|
|
55
|
+
- The `latchkey auth browser` subcommand requires a graphical environment.
|
|
44
56
|
|
|
45
57
|
### Steps
|
|
46
58
|
|
|
47
59
|
```
|
|
48
60
|
npm install -g latchkey
|
|
61
|
+
|
|
62
|
+
# Optionally, if you intend to use `latchkey auth browser`:
|
|
49
63
|
latchkey ensure-browser
|
|
50
64
|
```
|
|
51
65
|
|
|
52
|
-
The `ensure-browser` command discovers and configures a browser
|
|
53
|
-
|
|
54
|
-
|
|
66
|
+
The `ensure-browser` command discovers and configures a browser
|
|
67
|
+
for Latchkey to use. It searches for Chrome, Chromium, or Edge
|
|
68
|
+
on your system. If none is found, it downloads Chromium via
|
|
69
|
+
Playwright.
|
|
55
70
|
|
|
56
71
|
## Integrations
|
|
57
72
|
|
|
58
|
-
Warning: giving AI agents access to your API credentials is
|
|
59
|
-
dangerous
|
|
60
|
-
|
|
73
|
+
Warning: giving AI agents access to your API credentials is
|
|
74
|
+
potentially dangerous, especially when using the `auth browser`
|
|
75
|
+
feature. They will be able to perform most of the actions you
|
|
76
|
+
can. Only do this if you're willing to accept the risks.
|
|
61
77
|
|
|
62
78
|
|
|
63
79
|
### OpenCode
|
|
@@ -80,7 +96,9 @@ latchkey skill-md > ~/.codex/skills/latchkey/SKILL.md
|
|
|
80
96
|
|
|
81
97
|
### Passepartout
|
|
82
98
|
|
|
83
|
-
Check out our [Passepartout demo app](https://github.com/imbue-ai/passepartout)
|
|
99
|
+
Check out our [Passepartout demo app](https://github.com/imbue-ai/passepartout)
|
|
100
|
+
for an idea of how to build AI assistants for non-technical
|
|
101
|
+
users on top of Latchkey.
|
|
84
102
|
|
|
85
103
|
|
|
86
104
|
## Demo
|
|
@@ -98,31 +116,40 @@ latchkey curl -X POST 'https://slack.com/api/conversations.create' \
|
|
|
98
116
|
-d '{"name":"something-urgent"}'
|
|
99
117
|
```
|
|
100
118
|
|
|
101
|
-
Notice that `-H 'Authorization: Bearer ...'` is absent. This is
|
|
119
|
+
Notice that `-H 'Authorization: Bearer ...'` is absent. This is
|
|
120
|
+
because Latchkey injects stored credentials automatically. To
|
|
121
|
+
set up credentials for a service (Slack in this example), run:
|
|
102
122
|
|
|
103
|
-
|
|
104
|
-
|
|
105
|
-
|
|
106
|
-
|
|
123
|
+
```
|
|
124
|
+
latchkey auth browser slack
|
|
125
|
+
```
|
|
126
|
+
|
|
127
|
+
This opens the browser with a login screen. After you log in, Latchkey extracts
|
|
128
|
+
the necessary API credentials from the browser session, closes the browser, and
|
|
129
|
+
stores the credentials so that they can be reused.
|
|
107
130
|
|
|
108
|
-
|
|
109
|
-
|
|
110
|
-
|
|
111
|
-
|
|
131
|
+
Alternatively, you can provide credentials manually:
|
|
132
|
+
|
|
133
|
+
```
|
|
134
|
+
latchkey auth set slack -H "Authorization: Bearer xoxb-your-token"
|
|
135
|
+
```
|
|
136
|
+
|
|
137
|
+
`latchkey curl` passes your arguments straight through to `curl`
|
|
138
|
+
so you can use the same interface you are used to. The return
|
|
139
|
+
code, stdout and stderr are passed back from curl to the caller
|
|
140
|
+
of `latchkey`.
|
|
112
141
|
|
|
113
142
|
### Remembering API credentials
|
|
114
143
|
|
|
115
|
-
Your API credentials and browser state are
|
|
116
|
-
under `~/.latchkey`.
|
|
117
|
-
(which is the case on most systems), the data is properly
|
|
118
|
-
encrypted.
|
|
144
|
+
Your API credentials and browser state are encrypted and stored
|
|
145
|
+
by default under `~/.latchkey`.
|
|
119
146
|
|
|
120
147
|
|
|
121
148
|
### Inspecting the status of stored credentials
|
|
122
149
|
|
|
123
|
-
Calling `latchkey
|
|
124
|
-
|
|
125
|
-
|
|
150
|
+
Calling `latchkey services info <service_name>` will show information
|
|
151
|
+
about the service, including the credentials status. The
|
|
152
|
+
credentials status line will show one of:
|
|
126
153
|
|
|
127
154
|
- `missing`
|
|
128
155
|
- `invalid`
|
|
@@ -132,30 +159,42 @@ given service. Possible results are:
|
|
|
132
159
|
|
|
133
160
|
Remembered API credentials can expire. The caller of `latchkey
|
|
134
161
|
curl` will typically notice this because the calls will start returning
|
|
135
|
-
HTTP 401 or 403. To verify that, first call `latchkey
|
|
162
|
+
HTTP 401 or 403. To verify that, first call `latchkey services info`, e.g.:
|
|
163
|
+
|
|
164
|
+
```
|
|
165
|
+
latchkey services info discord
|
|
166
|
+
```
|
|
167
|
+
|
|
168
|
+
If the credentials status is `invalid`, it means the Unauthorized/Forbidden
|
|
169
|
+
responses are caused by invalid or expired credentials rather than insufficient
|
|
170
|
+
permissions. In that case, log in again:
|
|
136
171
|
|
|
137
172
|
```
|
|
138
|
-
latchkey
|
|
173
|
+
latchkey auth browser discord
|
|
139
174
|
```
|
|
140
175
|
|
|
141
|
-
|
|
142
|
-
caused by invalid or expired credentials rather than insufficient permissions,
|
|
143
|
-
force a new login in the next `latchkey curl` call by clearing the remembered
|
|
144
|
-
API credentials for the service in question, e.g.:
|
|
176
|
+
Or alternatively:
|
|
145
177
|
|
|
146
178
|
```
|
|
147
|
-
latchkey
|
|
179
|
+
latchkey auth set discord -H "Authorization: ..."
|
|
148
180
|
```
|
|
149
181
|
|
|
150
|
-
The next `latchkey curl` call will then trigger a new login flow.
|
|
151
182
|
|
|
152
|
-
|
|
153
|
-
|
|
183
|
+
### Clearing credentials and logins
|
|
184
|
+
|
|
185
|
+
In case you want to remove stored API credentials, use the `auth clear` subcommand.
|
|
154
186
|
|
|
155
187
|
```
|
|
156
|
-
latchkey clear
|
|
188
|
+
latchkey auth clear discord
|
|
157
189
|
```
|
|
158
190
|
|
|
191
|
+
To clear all stored data (both the credential store and browser state file), run:
|
|
192
|
+
|
|
193
|
+
```
|
|
194
|
+
latchkey auth clear
|
|
195
|
+
```
|
|
196
|
+
|
|
197
|
+
|
|
159
198
|
### Advanced configuration
|
|
160
199
|
|
|
161
200
|
You can set these environment variables to override certain
|
|
@@ -166,17 +205,19 @@ containing stored API credentials
|
|
|
166
205
|
- `LATCHKEY_BROWSER_STATE`: path to the (typically encrypted) file
|
|
167
206
|
containing the state (cookies, local storage, etc.) of
|
|
168
207
|
the browser used for the login popup
|
|
169
|
-
- `
|
|
208
|
+
- `LATCHKEY_CURL`: path to the curl binary
|
|
170
209
|
- `LATCHKEY_CONFIG`: path to the configuration file
|
|
171
210
|
(defaults to `~/.latchkey/config.json`)
|
|
172
211
|
- `LATCHKEY_KEYRING_SERVICE_NAME`, `LATCHKEY_KEYRING_ACCOUNT_NAME`: identifiers that are used to store the encryption password in your keyring
|
|
212
|
+
- `LATCHKEY_ENCRYPTION_KEY`: override the encryption key, e.g. when a keyring is not available. Example: `export LATCHKEY_ENCRYPTION_KEY="$(openssl rand -base64 32)"`
|
|
213
|
+
- `LATCHKEY_DISABLE_BROWSER`: when set (to any non-empty value), disables the browser login flow; commands that would trigger a browser login (`auth browser`, `auth browser-prepare`) will fail with an error instead
|
|
173
214
|
|
|
174
215
|
|
|
175
216
|
## Disclaimers
|
|
176
217
|
|
|
177
218
|
- This is still a work in progress.
|
|
178
219
|
- Latchkey has been created with the help of AI-assisted coding tools with careful human curation.
|
|
179
|
-
- Invoking `latchkey
|
|
220
|
+
- Invoking `latchkey auth browser ...` can sometimes have side effects in the form of
|
|
180
221
|
new API keys being created in your accounts (through browser automation).
|
|
181
222
|
- Using agents for automated access may be prohibited by some services' ToS.
|
|
182
223
|
- We reserve the right to change the license of future releases of Latchkey.
|
|
@@ -1,26 +1,26 @@
|
|
|
1
1
|
---
|
|
2
2
|
name: latchkey
|
|
3
|
-
description: Interact with third-party services (Slack, Google Workspace, Dropbox, GitHub, Linear...) on user's behalf using their public APIs.
|
|
4
|
-
compatibility: Requires node.js, curl
|
|
3
|
+
description: Interact with third-party services (Slack, Google Workspace, Dropbox, GitHub, Linear...) on the user's behalf using their public APIs.
|
|
4
|
+
compatibility: Requires node.js, curl and latchkey (npm install -g latchkey). A desktop/GUI environment is required for the browser functionality.
|
|
5
5
|
---
|
|
6
6
|
|
|
7
7
|
# Latchkey
|
|
8
8
|
|
|
9
9
|
## Instructions
|
|
10
10
|
|
|
11
|
-
Latchkey is a CLI tool that automatically injects credentials into curl commands for supported public APIs.
|
|
11
|
+
Latchkey is a CLI tool that automatically injects credentials into curl commands for supported public APIs. Credentials (mostly API tokens) can be either manually managed or, for some services, Latchkey can open a browser login pop-up window and extract API credentials from the session.
|
|
12
12
|
|
|
13
|
-
Use this skill when the user asks you to work with third-party services like Slack, Discord, Dropbox,
|
|
13
|
+
Use this skill when the user asks you to work with third-party services like Slack, Discord, Dropbox, GitHub, Linear and others on their behalf.
|
|
14
14
|
|
|
15
15
|
Usage:
|
|
16
16
|
|
|
17
17
|
1. **Use `latchkey curl`** instead of regular `curl` for supported services.
|
|
18
|
-
2. **
|
|
19
|
-
3. **
|
|
20
|
-
4. **
|
|
21
|
-
5. **
|
|
22
|
-
6.
|
|
23
|
-
7. **Do not
|
|
18
|
+
2. **Pass through all regular curl arguments** - latchkey is a transparent wrapper.
|
|
19
|
+
3. **Use `latchkey services list`** to get a list of supported services.
|
|
20
|
+
4. **Use `latchkey services info <service_name>`** to get information about a specific service (auth options, credentials status, API docs links, special requirements, etc.).
|
|
21
|
+
5. **If necessary, get or renew credentials first.** Run `latchkey auth browser <service_name>` to open a browser login pop-up window if supported.
|
|
22
|
+
6. **Look for the newest documentation of the desired public API online.** If using the `browser` auth command, avoid bot-only endpoints.
|
|
23
|
+
7. **Do not initiate a new login if the credentials status is `valid`** - the user might just not have the necessary permissions for the action you're trying to do.
|
|
24
24
|
|
|
25
25
|
|
|
26
26
|
## Examples
|
|
@@ -44,28 +44,34 @@ latchkey curl -X POST 'https://slack.com/api/conversations.create' \
|
|
|
44
44
|
latchkey curl 'https://discord.com/api/v10/users/@me'
|
|
45
45
|
```
|
|
46
46
|
|
|
47
|
-
###
|
|
47
|
+
### Detect expired credentials and force a new login to Discord
|
|
48
48
|
```bash
|
|
49
|
-
latchkey
|
|
50
|
-
latchkey
|
|
49
|
+
latchkey services info discord # Check the "credentialStatus" field - shows "invalid"
|
|
50
|
+
latchkey auth browser discord
|
|
51
51
|
latchkey curl 'https://discord.com/api/v10/users/@me'
|
|
52
52
|
```
|
|
53
53
|
|
|
54
|
-
Only do this when you notice that your previous call ended up not being authenticated (HTTP 401 or 403).
|
|
54
|
+
Only do this when you notice that your previous call ended up not being authenticated (HTTP 401 or 403).
|
|
55
55
|
|
|
56
|
-
### List
|
|
56
|
+
### List available services
|
|
57
57
|
```bash
|
|
58
|
-
latchkey services
|
|
58
|
+
latchkey services list
|
|
59
59
|
```
|
|
60
60
|
|
|
61
|
+
Lists all services that latchkey knows about.
|
|
62
|
+
|
|
61
63
|
### Get service-specific info
|
|
62
64
|
```bash
|
|
63
|
-
latchkey info slack
|
|
65
|
+
latchkey services info slack
|
|
64
66
|
```
|
|
65
67
|
|
|
66
|
-
Returns
|
|
68
|
+
Returns auth options, credentials status, and developer notes
|
|
69
|
+
about the service. If `browser` is not present in the
|
|
70
|
+
`authOptions` field, the service requires the user to directly
|
|
71
|
+
set API credentials via `latchkey auth set` before making
|
|
72
|
+
requests.
|
|
67
73
|
|
|
68
74
|
## Notes
|
|
69
75
|
|
|
70
76
|
- All curl arguments are passed through unchanged
|
|
71
|
-
- Return
|
|
77
|
+
- Return code, stdout and stderr are passed back from curl
|
package/dist/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "latchkey",
|
|
3
|
-
"version": "0.
|
|
3
|
+
"version": "1.0.1",
|
|
4
4
|
"description": "A CLI tool that injects API credentials into curl requests for known third-party services",
|
|
5
5
|
"author": "Imbue <hynek@imbue.com>",
|
|
6
6
|
"repository": {
|
|
@@ -52,7 +52,7 @@
|
|
|
52
52
|
"dependencies": {
|
|
53
53
|
"@napi-rs/keyring": "^1.2.0",
|
|
54
54
|
"commander": "^12.0.0",
|
|
55
|
-
"playwright": "^1.
|
|
55
|
+
"playwright": "^1.58.2",
|
|
56
56
|
"zod": "^3.22.0"
|
|
57
57
|
},
|
|
58
58
|
"devDependencies": {
|
|
@@ -0,0 +1,27 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Generates TypeScript code from recorded actions.
|
|
3
|
+
* Uses page.getByRole where possible and outputs element ancestry for AI post-processing.
|
|
4
|
+
*/
|
|
5
|
+
import type { ElementInfo, RecordedAction } from './types.js';
|
|
6
|
+
export declare class CodeGenerator {
|
|
7
|
+
private readonly actions;
|
|
8
|
+
private readonly outputPath;
|
|
9
|
+
private actionCounter;
|
|
10
|
+
private initialUrl;
|
|
11
|
+
private apiKeyAncestry;
|
|
12
|
+
constructor(outputPath: string);
|
|
13
|
+
setInitialUrl(url: string): void;
|
|
14
|
+
addAction(action: RecordedAction): void;
|
|
15
|
+
setApiKeyAncestry(ancestry: ElementInfo[]): void;
|
|
16
|
+
private escapeString;
|
|
17
|
+
private generateGetByRole;
|
|
18
|
+
private generateGetByPlaceholder;
|
|
19
|
+
private generateGetByLabel;
|
|
20
|
+
private generateLocator;
|
|
21
|
+
private formatElementInfo;
|
|
22
|
+
private formatAncestryComments;
|
|
23
|
+
private generateActionCode;
|
|
24
|
+
generateCode(): string;
|
|
25
|
+
flush(): void;
|
|
26
|
+
}
|
|
27
|
+
//# sourceMappingURL=codeGenerator.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"codeGenerator.d.ts","sourceRoot":"","sources":["../../../scripts/codegen/codeGenerator.ts"],"names":[],"mappings":"AAAA;;;GAGG;AAGH,OAAO,KAAK,EAAE,WAAW,EAAE,cAAc,EAAE,MAAM,YAAY,CAAC;AAE9D,qBAAa,aAAa;IACxB,OAAO,CAAC,QAAQ,CAAC,OAAO,CAAwB;IAChD,OAAO,CAAC,QAAQ,CAAC,UAAU,CAAS;IACpC,OAAO,CAAC,aAAa,CAAK;IAC1B,OAAO,CAAC,UAAU,CAAqB;IACvC,OAAO,CAAC,cAAc,CAA4B;gBAEtC,UAAU,EAAE,MAAM;IAI9B,aAAa,CAAC,GAAG,EAAE,MAAM,GAAG,IAAI;IAKhC,SAAS,CAAC,MAAM,EAAE,cAAc,GAAG,IAAI;IAKvC,iBAAiB,CAAC,QAAQ,EAAE,WAAW,EAAE,GAAG,IAAI;IAKhD,OAAO,CAAC,YAAY;IAQpB,OAAO,CAAC,iBAAiB;IAYzB,OAAO,CAAC,wBAAwB;IAKhC,OAAO,CAAC,kBAAkB;IAO1B,OAAO,CAAC,eAAe;IA8BvB,OAAO,CAAC,iBAAiB;IA4BzB,OAAO,CAAC,sBAAsB;IAkB9B,OAAO,CAAC,kBAAkB;IAuD1B,YAAY,IAAI,MAAM;IAwDtB,KAAK,IAAI,IAAI;CAGd"}
|
|
@@ -0,0 +1,220 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Generates TypeScript code from recorded actions.
|
|
3
|
+
* Uses page.getByRole where possible and outputs element ancestry for AI post-processing.
|
|
4
|
+
*/
|
|
5
|
+
import { writeFileSync } from 'node:fs';
|
|
6
|
+
export class CodeGenerator {
|
|
7
|
+
actions = [];
|
|
8
|
+
outputPath;
|
|
9
|
+
actionCounter = 0;
|
|
10
|
+
initialUrl;
|
|
11
|
+
apiKeyAncestry;
|
|
12
|
+
constructor(outputPath) {
|
|
13
|
+
this.outputPath = outputPath;
|
|
14
|
+
}
|
|
15
|
+
setInitialUrl(url) {
|
|
16
|
+
this.initialUrl = url;
|
|
17
|
+
this.flush();
|
|
18
|
+
}
|
|
19
|
+
addAction(action) {
|
|
20
|
+
this.actions.push(action);
|
|
21
|
+
this.flush();
|
|
22
|
+
}
|
|
23
|
+
setApiKeyAncestry(ancestry) {
|
|
24
|
+
this.apiKeyAncestry = ancestry;
|
|
25
|
+
this.flush();
|
|
26
|
+
}
|
|
27
|
+
escapeString(str) {
|
|
28
|
+
return str
|
|
29
|
+
.replace(/\\/g, '\\\\')
|
|
30
|
+
.replace(/'/g, "\\'")
|
|
31
|
+
.replace(/\n/g, '\\n')
|
|
32
|
+
.replace(/\r/g, '\\r');
|
|
33
|
+
}
|
|
34
|
+
generateGetByRole(element) {
|
|
35
|
+
if (!element.role)
|
|
36
|
+
return null;
|
|
37
|
+
const role = element.role;
|
|
38
|
+
const name = element.accessibleName;
|
|
39
|
+
if (name) {
|
|
40
|
+
return `page.getByRole('${role}', { name: '${this.escapeString(name)}' })`;
|
|
41
|
+
}
|
|
42
|
+
return `page.getByRole('${role}')`;
|
|
43
|
+
}
|
|
44
|
+
generateGetByPlaceholder(element) {
|
|
45
|
+
if (!element.placeholder)
|
|
46
|
+
return null;
|
|
47
|
+
return `page.getByPlaceholder('${this.escapeString(element.placeholder)}')`;
|
|
48
|
+
}
|
|
49
|
+
generateGetByLabel(element) {
|
|
50
|
+
if (!element.accessibleName)
|
|
51
|
+
return null;
|
|
52
|
+
if (element.tag !== 'input' && element.tag !== 'textarea' && element.tag !== 'select')
|
|
53
|
+
return null;
|
|
54
|
+
return `page.getByLabel('${this.escapeString(element.accessibleName)}')`;
|
|
55
|
+
}
|
|
56
|
+
generateLocator(target) {
|
|
57
|
+
// Try getByRole first (Playwright best practice)
|
|
58
|
+
let locator = this.generateGetByRole(target);
|
|
59
|
+
if (locator) {
|
|
60
|
+
return { locator, strategy: 'getByRole' };
|
|
61
|
+
}
|
|
62
|
+
// Try getByPlaceholder
|
|
63
|
+
locator = this.generateGetByPlaceholder(target);
|
|
64
|
+
if (locator) {
|
|
65
|
+
return { locator, strategy: 'getByPlaceholder' };
|
|
66
|
+
}
|
|
67
|
+
// Try getByLabel
|
|
68
|
+
locator = this.generateGetByLabel(target);
|
|
69
|
+
if (locator) {
|
|
70
|
+
return { locator, strategy: 'getByLabel' };
|
|
71
|
+
}
|
|
72
|
+
// Fallback to locator with a simple selector
|
|
73
|
+
if (target.id) {
|
|
74
|
+
return { locator: `page.locator('#${target.id}')`, strategy: 'id' };
|
|
75
|
+
}
|
|
76
|
+
if (target.className) {
|
|
77
|
+
const firstClass = target.className.split(/\s+/)[0] ?? '';
|
|
78
|
+
return { locator: `page.locator('.${firstClass}')`, strategy: 'class' };
|
|
79
|
+
}
|
|
80
|
+
return { locator: `page.locator('${target.tag}')`, strategy: 'tag' };
|
|
81
|
+
}
|
|
82
|
+
formatElementInfo(element) {
|
|
83
|
+
const parts = [`tag: ${element.tag}`];
|
|
84
|
+
if (element.id) {
|
|
85
|
+
parts.push(`id: "${element.id}"`);
|
|
86
|
+
}
|
|
87
|
+
if (element.className) {
|
|
88
|
+
parts.push(`class: "${element.className}"`);
|
|
89
|
+
}
|
|
90
|
+
if (element.name) {
|
|
91
|
+
parts.push(`name: "${element.name}"`);
|
|
92
|
+
}
|
|
93
|
+
if (element.role) {
|
|
94
|
+
parts.push(`role: ${element.role}`);
|
|
95
|
+
}
|
|
96
|
+
if (element.accessibleName) {
|
|
97
|
+
parts.push(`accessibleName: "${this.escapeString(element.accessibleName)}"`);
|
|
98
|
+
}
|
|
99
|
+
if (element.inputType) {
|
|
100
|
+
parts.push(`type: ${element.inputType}`);
|
|
101
|
+
}
|
|
102
|
+
if (element.placeholder) {
|
|
103
|
+
parts.push(`placeholder: "${this.escapeString(element.placeholder)}"`);
|
|
104
|
+
}
|
|
105
|
+
return `{ ${parts.join(', ')} }`;
|
|
106
|
+
}
|
|
107
|
+
formatAncestryComments(ancestry) {
|
|
108
|
+
const lines = [];
|
|
109
|
+
lines.push(` // Element ancestry (root -> target):`);
|
|
110
|
+
// Output ancestry in reverse order (root first, target last)
|
|
111
|
+
for (let i = ancestry.length - 1; i >= 0; i--) {
|
|
112
|
+
const element = ancestry[i];
|
|
113
|
+
if (element) {
|
|
114
|
+
const depth = ancestry.length - 1 - i;
|
|
115
|
+
const indent = ' '.repeat(depth);
|
|
116
|
+
const marker = i === 0 ? ' [TARGET]' : '';
|
|
117
|
+
lines.push(` // ${indent}${this.formatElementInfo(element)}${marker}`);
|
|
118
|
+
}
|
|
119
|
+
}
|
|
120
|
+
return lines;
|
|
121
|
+
}
|
|
122
|
+
generateActionCode(action) {
|
|
123
|
+
// Navigation doesn't need ancestry
|
|
124
|
+
if (action.type === 'navigate') {
|
|
125
|
+
return ` await page.goto('${this.escapeString(action.url ?? '')}');`;
|
|
126
|
+
}
|
|
127
|
+
const ancestry = action.ancestry ?? [];
|
|
128
|
+
const target = ancestry[0];
|
|
129
|
+
if (!target) {
|
|
130
|
+
return ` // Action ${action.type} with no element info`;
|
|
131
|
+
}
|
|
132
|
+
this.actionCounter++;
|
|
133
|
+
const actionId = this.actionCounter;
|
|
134
|
+
// Determine the action method
|
|
135
|
+
let actionMethod;
|
|
136
|
+
switch (action.type) {
|
|
137
|
+
case 'click':
|
|
138
|
+
actionMethod = '.click()';
|
|
139
|
+
break;
|
|
140
|
+
case 'fill':
|
|
141
|
+
actionMethod = `.fill('${this.escapeString(action.value ?? '')}')`;
|
|
142
|
+
break;
|
|
143
|
+
case 'press':
|
|
144
|
+
actionMethod = `.press('${this.escapeString(action.key ?? '')}')`;
|
|
145
|
+
break;
|
|
146
|
+
case 'select':
|
|
147
|
+
actionMethod = `.selectOption('${this.escapeString(action.value ?? '')}')`;
|
|
148
|
+
break;
|
|
149
|
+
case 'check':
|
|
150
|
+
actionMethod = '.check()';
|
|
151
|
+
break;
|
|
152
|
+
case 'uncheck':
|
|
153
|
+
actionMethod = '.uncheck()';
|
|
154
|
+
break;
|
|
155
|
+
default: {
|
|
156
|
+
const unknownType = action.type;
|
|
157
|
+
return ` // Unknown action: ${String(unknownType)}`;
|
|
158
|
+
}
|
|
159
|
+
}
|
|
160
|
+
const { locator: primaryLocator, strategy: locatorType } = this.generateLocator(target);
|
|
161
|
+
// Build the output with ancestry information (root -> target order)
|
|
162
|
+
const lines = [];
|
|
163
|
+
lines.push(` // ===== ACTION ${String(actionId)}: ${action.type} =====`);
|
|
164
|
+
lines.push(...this.formatAncestryComments(ancestry));
|
|
165
|
+
lines.push(` // Locator strategy: ${locatorType}`);
|
|
166
|
+
lines.push(` await ${primaryLocator}${actionMethod};`);
|
|
167
|
+
lines.push('');
|
|
168
|
+
return lines.join('\n');
|
|
169
|
+
}
|
|
170
|
+
generateCode() {
|
|
171
|
+
// Reset counter for consistent output
|
|
172
|
+
this.actionCounter = 0;
|
|
173
|
+
// Generate initial URL navigation if set
|
|
174
|
+
const initialUrlCode = this.initialUrl
|
|
175
|
+
? ` await page.goto('${this.escapeString(this.initialUrl)}');\n\n`
|
|
176
|
+
: '';
|
|
177
|
+
const header = `// Generated by Latchkey Codegen
|
|
178
|
+
// Each action includes element ancestry for AI post-processing to synthesize optimal selectors.
|
|
179
|
+
// The active locator uses page.getByRole where possible (Playwright best practice).
|
|
180
|
+
|
|
181
|
+
const { chromium } = require('playwright');
|
|
182
|
+
|
|
183
|
+
(async () => {
|
|
184
|
+
const browser = await chromium.launch({ headless: false });
|
|
185
|
+
const context = await browser.newContext();
|
|
186
|
+
const page = await context.newPage();
|
|
187
|
+
|
|
188
|
+
${initialUrlCode}`;
|
|
189
|
+
const footer = ` // ---------------------
|
|
190
|
+
await context.close();
|
|
191
|
+
await browser.close();
|
|
192
|
+
})();
|
|
193
|
+
`;
|
|
194
|
+
const actionLines = this.actions.map((action) => this.generateActionCode(action));
|
|
195
|
+
// Generate API key extraction code if ancestry was set
|
|
196
|
+
let apiKeyCode = '';
|
|
197
|
+
if (this.apiKeyAncestry && this.apiKeyAncestry.length > 0) {
|
|
198
|
+
const ancestry = this.apiKeyAncestry;
|
|
199
|
+
const target = ancestry[0];
|
|
200
|
+
if (target) {
|
|
201
|
+
const { locator: primaryLocator, strategy: locatorType } = this.generateLocator(target);
|
|
202
|
+
// Build ancestry information
|
|
203
|
+
const ancestryLines = [];
|
|
204
|
+
ancestryLines.push(` // ===== API KEY EXTRACTION =====`);
|
|
205
|
+
ancestryLines.push(...this.formatAncestryComments(ancestry));
|
|
206
|
+
ancestryLines.push(` // Locator strategy: ${locatorType}`);
|
|
207
|
+
ancestryLines.push(` const apiKey = await ${primaryLocator}.textContent();`);
|
|
208
|
+
ancestryLines.push(` console.log('API Key:', apiKey);`);
|
|
209
|
+
ancestryLines.push(` // ===== END API KEY EXTRACTION =====`);
|
|
210
|
+
ancestryLines.push('');
|
|
211
|
+
apiKeyCode = '\n' + ancestryLines.join('\n') + '\n';
|
|
212
|
+
}
|
|
213
|
+
}
|
|
214
|
+
return header + actionLines.join('\n') + apiKeyCode + footer;
|
|
215
|
+
}
|
|
216
|
+
flush() {
|
|
217
|
+
writeFileSync(this.outputPath, this.generateCode(), 'utf-8');
|
|
218
|
+
}
|
|
219
|
+
}
|
|
220
|
+
//# sourceMappingURL=codeGenerator.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"codeGenerator.js","sourceRoot":"","sources":["../../../scripts/codegen/codeGenerator.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,27 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Codegen module that records browser actions and generates TypeScript code:
|
|
3
|
+
* - Records user interactions (clicks, fills, navigations, etc.)
|
|
4
|
+
* - Always generates TypeScript code
|
|
5
|
+
* - Records all HTTP request metadata to a file
|
|
6
|
+
* - Includes a custom toolbar with additional buttons
|
|
7
|
+
*
|
|
8
|
+
* The session has two phases:
|
|
9
|
+
* - Pre-login: No recording, requests marked as pre-login
|
|
10
|
+
* - Post-login: User interactions are recorded, requests marked as post-login
|
|
11
|
+
*/
|
|
12
|
+
import type { CodegenOptions, CodegenResult } from './types.js';
|
|
13
|
+
export type { CodegenOptions, CodegenResult, ElementInfo, RecordedAction, RecordingPhase, RequestMetadata, } from './types.js';
|
|
14
|
+
export { CodegenError } from './types.js';
|
|
15
|
+
/**
|
|
16
|
+
* Run the codegen which opens a browser with recording enabled.
|
|
17
|
+
* Injects a custom toolbar and records user actions and HTTP request metadata.
|
|
18
|
+
*
|
|
19
|
+
* Creates a scripts/recordings/$name/ directory with:
|
|
20
|
+
* - actions.js: Recorded user actions
|
|
21
|
+
* - requests.json: HTTP request metadata
|
|
22
|
+
* - prompt.txt: Instructions for creating a service definition
|
|
23
|
+
*
|
|
24
|
+
* @returns Result containing the API key ancestry if selected by the user
|
|
25
|
+
*/
|
|
26
|
+
export declare function runCodegen(options: CodegenOptions): Promise<CodegenResult>;
|
|
27
|
+
//# sourceMappingURL=index.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../../scripts/codegen/index.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;GAUG;AAWH,OAAO,KAAK,EACV,cAAc,EACd,aAAa,EAId,MAAM,YAAY,CAAC;AAUpB,YAAY,EACV,cAAc,EACd,aAAa,EACb,WAAW,EACX,cAAc,EACd,cAAc,EACd,eAAe,GAChB,MAAM,YAAY,CAAC;AACpB,OAAO,EAAE,YAAY,EAAE,MAAM,YAAY,CAAC;AAyB1C;;;;;;;;;;GAUG;AACH,wBAAsB,UAAU,CAAC,OAAO,EAAE,cAAc,GAAG,OAAO,CAAC,aAAa,CAAC,CAuKhF"}
|