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.
Files changed (118) hide show
  1. package/README.md +98 -57
  2. package/dist/integrations/SKILL.md +25 -19
  3. package/dist/package.json +2 -2
  4. package/dist/scripts/codegen/codeGenerator.d.ts +27 -0
  5. package/dist/scripts/codegen/codeGenerator.d.ts.map +1 -0
  6. package/dist/scripts/codegen/codeGenerator.js +220 -0
  7. package/dist/scripts/codegen/codeGenerator.js.map +1 -0
  8. package/dist/scripts/codegen/index.d.ts +27 -0
  9. package/dist/scripts/codegen/index.d.ts.map +1 -0
  10. package/dist/scripts/codegen/index.js +189 -0
  11. package/dist/scripts/codegen/index.js.map +1 -0
  12. package/dist/scripts/codegen/injectedScript.d.ts +6 -0
  13. package/dist/scripts/codegen/injectedScript.d.ts.map +1 -0
  14. package/dist/scripts/codegen/injectedScript.js +657 -0
  15. package/dist/scripts/codegen/injectedScript.js.map +1 -0
  16. package/dist/scripts/codegen/requestMetadataCollector.d.ts +15 -0
  17. package/dist/scripts/codegen/requestMetadataCollector.d.ts.map +1 -0
  18. package/dist/scripts/codegen/requestMetadataCollector.js +48 -0
  19. package/dist/scripts/codegen/requestMetadataCollector.js.map +1 -0
  20. package/dist/scripts/codegen/types.d.ts +77 -0
  21. package/dist/scripts/codegen/types.d.ts.map +1 -0
  22. package/dist/scripts/codegen/types.js +10 -0
  23. package/dist/scripts/codegen/types.js.map +1 -0
  24. package/dist/scripts/codegen.d.ts +24 -0
  25. package/dist/scripts/codegen.d.ts.map +1 -0
  26. package/dist/scripts/codegen.js +95 -0
  27. package/dist/scripts/codegen.js.map +1 -0
  28. package/dist/scripts/cryptFile.js +7 -2
  29. package/dist/scripts/cryptFile.js.map +1 -1
  30. package/dist/src/apiCredentialStore.d.ts +1 -0
  31. package/dist/src/apiCredentialStore.d.ts.map +1 -1
  32. package/dist/src/apiCredentialStore.js +12 -0
  33. package/dist/src/apiCredentialStore.js.map +1 -1
  34. package/dist/src/apiCredentials.d.ts +33 -0
  35. package/dist/src/apiCredentials.d.ts.map +1 -1
  36. package/dist/src/apiCredentials.js +36 -0
  37. package/dist/src/apiCredentials.js.map +1 -1
  38. package/dist/src/cli.js +3 -2
  39. package/dist/src/cli.js.map +1 -1
  40. package/dist/src/cliCommands.d.ts.map +1 -1
  41. package/dist/src/cliCommands.js +158 -126
  42. package/dist/src/cliCommands.js.map +1 -1
  43. package/dist/src/config.d.ts +13 -0
  44. package/dist/src/config.d.ts.map +1 -1
  45. package/dist/src/config.js +56 -16
  46. package/dist/src/config.js.map +1 -1
  47. package/dist/src/encryptedStorage.d.ts +1 -2
  48. package/dist/src/encryptedStorage.d.ts.map +1 -1
  49. package/dist/src/encryptedStorage.js +18 -38
  50. package/dist/src/encryptedStorage.js.map +1 -1
  51. package/dist/src/index.d.ts +2 -2
  52. package/dist/src/index.d.ts.map +1 -1
  53. package/dist/src/index.js +3 -3
  54. package/dist/src/index.js.map +1 -1
  55. package/dist/src/keychain.d.ts +0 -4
  56. package/dist/src/keychain.d.ts.map +1 -1
  57. package/dist/src/keychain.js +0 -13
  58. package/dist/src/keychain.js.map +1 -1
  59. package/dist/src/oauthUtils.d.ts +1 -1
  60. package/dist/src/oauthUtils.d.ts.map +1 -1
  61. package/dist/src/playwrightUtils.d.ts +6 -0
  62. package/dist/src/playwrightUtils.d.ts.map +1 -1
  63. package/dist/src/playwrightUtils.js +12 -0
  64. package/dist/src/playwrightUtils.js.map +1 -1
  65. package/dist/src/registry.d.ts.map +1 -1
  66. package/dist/src/registry.js +20 -4
  67. package/dist/src/registry.js.map +1 -1
  68. package/dist/src/services/base.d.ts +20 -18
  69. package/dist/src/services/base.d.ts.map +1 -1
  70. package/dist/src/services/base.js +37 -1
  71. package/dist/src/services/base.js.map +1 -1
  72. package/dist/src/services/discord.d.ts +2 -3
  73. package/dist/src/services/discord.d.ts.map +1 -1
  74. package/dist/src/services/discord.js +3 -22
  75. package/dist/src/services/discord.js.map +1 -1
  76. package/dist/src/services/dropbox.d.ts +2 -3
  77. package/dist/src/services/dropbox.d.ts.map +1 -1
  78. package/dist/src/services/dropbox.js +3 -22
  79. package/dist/src/services/dropbox.js.map +1 -1
  80. package/dist/src/services/github.d.ts +2 -3
  81. package/dist/src/services/github.d.ts.map +1 -1
  82. package/dist/src/services/github.js +3 -22
  83. package/dist/src/services/github.js.map +1 -1
  84. package/dist/src/services/google.d.ts +3 -4
  85. package/dist/src/services/google.d.ts.map +1 -1
  86. package/dist/src/services/google.js +21 -43
  87. package/dist/src/services/google.js.map +1 -1
  88. package/dist/src/services/index.d.ts +2 -2
  89. package/dist/src/services/index.d.ts.map +1 -1
  90. package/dist/src/services/index.js +2 -1
  91. package/dist/src/services/index.js.map +1 -1
  92. package/dist/src/services/linear.d.ts +2 -3
  93. package/dist/src/services/linear.d.ts.map +1 -1
  94. package/dist/src/services/linear.js +3 -23
  95. package/dist/src/services/linear.js.map +1 -1
  96. package/dist/src/services/mailchimp.d.ts +11 -0
  97. package/dist/src/services/mailchimp.d.ts.map +1 -0
  98. package/dist/src/services/mailchimp.js +16 -0
  99. package/dist/src/services/mailchimp.js.map +1 -0
  100. package/dist/src/services/notion.d.ts +2 -3
  101. package/dist/src/services/notion.d.ts.map +1 -1
  102. package/dist/src/services/notion.js +3 -22
  103. package/dist/src/services/notion.js.map +1 -1
  104. package/dist/src/services/slack.d.ts +1 -1
  105. package/dist/src/services/slack.d.ts.map +1 -1
  106. package/dist/src/services/slack.js +2 -5
  107. package/dist/src/services/slack.js.map +1 -1
  108. package/dist/tests/apiCredentials.test.js +59 -1
  109. package/dist/tests/apiCredentials.test.js.map +1 -1
  110. package/dist/tests/cli.test.js +270 -128
  111. package/dist/tests/cli.test.js.map +1 -1
  112. package/dist/tests/playwrightDownload.test.js +2 -2
  113. package/dist/tests/playwrightDownload.test.js.map +1 -1
  114. package/dist/tests/registry.test.js +14 -2
  115. package/dist/tests/registry.test.js.map +1 -1
  116. package/dist/tests/servicesAgainstRecordings.test.js +3 -0
  117. package/dist/tests/servicesAgainstRecordings.test.js.map +1 -1
  118. package/package.json +2 -2
package/README.md CHANGED
@@ -1,10 +1,14 @@
1
1
  # Latchkey
2
2
 
3
- Turn browser logins into usable credentials for local agents.
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 to curl requests to known public APIs.
19
+ Latchkey is a command-line tool that injects credentials into curl
20
+ requests to known public APIs.
16
21
 
17
- - `latchkey services`
18
- - Get a list of known and supported third-party services (Slack, Google Workspace, Linear, GitHub, etc.).
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
- - (The first time you access a service, a browser pop-up with a login screen appears.)
22
-
23
- Latchkey is primarily designed for AI agents. By invoking Latchkey, agents can
24
- prompt the user to authenticate when needed, then continue interacting with
25
- third-party APIs using standard curl syntax - no custom integrations or embedded
26
- credentials required.
27
-
28
- Unlike OAuth-based flows or typical MCP-style integrations, Latchkey does not
29
- introduce an intermediary between the agent and the service. Requests are made
30
- directly on the user’s behalf, which enables greater flexibility at the cost of
31
- formal delegation: agents authenticate as the user.
32
-
33
- If a service you need isn’t supported yet, contributions are welcome. Adding
34
- support typically involves writing a small browser automation class that
35
- extracts API credentials after login. See the [development docs](docs/development.md)
36
- for details.
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 for Latchkey to use. It searches for Chrome, Chromium, or Edge on your system. If none is found, it downloads Chromium via Playwright.
53
-
54
- **nvm users**: Global packages are per node version. If you switch versions, reinstall with `npm install -g latchkey`
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 potentially
59
- dangerous. They will be able to perform most of the actions you can. Only do this if
60
- you're willing to accept the risks.
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) for an idea of how to build AI assistants for non-technical users on top of Latchkey.
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 because Latchkey:
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
- - Opens the browser with a login screen.
104
- - After the user logs in, Latchkey extracts the necessary API credentials from the browser session.
105
- - The browser is closed, the credentials are injected into the arguments, and `curl` is invoked.
106
- - The credentials are stored so that they can be reused the next time.
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
- Otherwise, `latchkey curl` passes your arguments straight
109
- through to `curl` so you can use the same interface you are used
110
- to. The return code, stdin and stdout are passed back from curl
111
- to the caller of `latchkey`.
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 stored by default
116
- under `~/.latchkey`. When a functioning keyring is detected
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 status <service_name>` will give you
124
- information about the status of remembered credentials for the
125
- given service. Possible results are:
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 status`, e.g.:
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 status discord
173
+ latchkey auth browser discord
139
174
  ```
140
175
 
141
- If the result is `invalid` , meaning the Unauthorized/Forbidden responses are
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 clear discord
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
- To clear all stored data (both the credentials store and browser
153
- state file), run:
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
- - `LATCHKEY_CURL_PATH`: path to the curl binary
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 curl ...` can sometimes have side effects in the form of
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, latchkey (npm install -g latchkey) and a desktop/GUI environment.
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. Instead of manually managing API tokens, latchkey opens a browser for login, extracts credentials from the session, and injects them into your curl requests.
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, Github, Linear and others on their behalf.
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. **Use `latchkey info <service_name>`** to get developer notes about a specific service (API docs links, special requirements, etc.).
19
- 3. **Look for the newest documentation of the desired public API online.** Avoid bot-only endpoints if such a distinction exists.
20
- 4. **Pass through all regular curl arguments** - latchkey is a transparent wrapper.
21
- 5. **Use `latchkey status <service_name>`** when you notice potentially expired credentials.
22
- 6. When the status is `invalid`, **force a new login by calling `latchkey clear <service_name>`**, then retry the curl command.
23
- 7. **Do not force a new login if the status is `valid`** - the user might just not have the necessary permissions.
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
- ### Clear expired credentials and force a new login to Discord
47
+ ### Detect expired credentials and force a new login to Discord
48
48
  ```bash
49
- latchkey status discord # Returns "invalid"
50
- latchkey clear discord
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). The next `latchkey curl` call will trigger a new login flow.
54
+ Only do this when you notice that your previous call ended up not being authenticated (HTTP 401 or 403).
55
55
 
56
- ### List supported services
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 developer notes about the service, including API documentation links and any special requirements.
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 codes, stdin, and stdout are passed back from curl
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.2.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.49.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"}