imprint-mcp 0.6.0 → 0.6.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/package.json +2 -1
- package/prompts/auth-compile-agent.md +149 -158
- package/prompts/build-planning.md +14 -9
- package/prompts/tool-candidate-detection.md +9 -29
- package/src/imprint/auth-compile-agent.ts +215 -155
- package/src/imprint/auth-compile-tools.ts +300 -118
- package/src/imprint/auth-verifier.ts +167 -180
- package/src/imprint/backend-ladder.ts +179 -145
- package/src/imprint/build-plan.ts +3 -8
- package/src/imprint/cdp-browser-fetch.ts +837 -83
- package/src/imprint/claude-cli-compile.ts +8 -4
- package/src/imprint/codex-cli-compile.ts +322 -124
- package/src/imprint/compile-agent-types.ts +15 -10
- package/src/imprint/compile-agent.ts +17 -2
- package/src/imprint/compile-tools.ts +59 -1
- package/src/imprint/credential-store.ts +57 -44
- package/src/imprint/emit.ts +3 -1
- package/src/imprint/llm.ts +6 -3
- package/src/imprint/login.ts +107 -25
- package/src/imprint/mcp-compile-server.ts +81 -47
- package/src/imprint/mcp-server.ts +104 -33
- package/src/imprint/recording-request.ts +36 -0
- package/src/imprint/request-capture.ts +40 -17
- package/src/imprint/runtime.ts +437 -334
- package/src/imprint/teach-state.ts +18 -1
- package/src/imprint/teach.ts +225 -127
- package/src/imprint/tool-candidates.ts +8 -10
- package/src/imprint/tool-loader.ts +12 -4
- package/src/imprint/types.ts +100 -68
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "imprint-mcp",
|
|
3
|
-
"version": "0.6.
|
|
3
|
+
"version": "0.6.1",
|
|
4
4
|
"description": "Teach an AI agent how to use any website. Once. Records a real browser session + narration; generates a deterministic MCP tool plus a DOM-replay playbook fallback.",
|
|
5
5
|
"type": "module",
|
|
6
6
|
"exports": {
|
|
@@ -65,6 +65,7 @@
|
|
|
65
65
|
"puppeteer-extra-plugin-stealth": "^2.11.2",
|
|
66
66
|
"redactum": "^1.1.0",
|
|
67
67
|
"semver": "^7.8.4",
|
|
68
|
+
"tldts": "^7.4.8",
|
|
68
69
|
"yaml": "^2.8.4",
|
|
69
70
|
"zod": "^3.24.0"
|
|
70
71
|
},
|
|
@@ -1,165 +1,156 @@
|
|
|
1
|
-
#
|
|
2
|
-
|
|
3
|
-
|
|
4
|
-
|
|
5
|
-
|
|
6
|
-
|
|
7
|
-
|
|
8
|
-
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
5. **Get the live second factor.** Call `prompt_user` with a clear message (and `options` if it's a choice), then STOP. The orchestrator collects the user's input and resumes you with it.
|
|
44
|
-
|
|
45
|
-
6. **Verify phase 2 (complete the login).** Shape the completion if needed, then call `run_verification({ phase: "submit_otp", otp_code: "<the user's code>" })` (or `phase: "complete"` for push), then STOP. On `ok`, the login finished and the session token is stored → call `done`. On failure, decide cool-off vs defect as in step 4.
|
|
46
|
-
|
|
47
|
-
7. **Finish.** Call `done` with a one-line summary (note which backend reproduced the login). Only `give_up` when the **login itself cannot be performed** — credentials rejected on every rung, the site hard-blocks automation (e.g. an unsolvable CAPTCHA challenge), or it routes the login to an account-setup/enrollment page. Never loosen a success marker to fake success.
|
|
48
|
-
|
|
49
|
-
## Persist the session token for data tools (`sessionCapture`)
|
|
50
|
-
|
|
51
|
-
The point of completing the login is a **durable token the data tools reuse without re-running auth** (they re-auth only when it expires). Cookies are persisted automatically. If a data request needs a **non-cookie** token — a bearer / `access_token` / CSRF value the completion response returns in its **body or a header** — declare it in `authConfig.sessionCapture` (same shape as a request `capture`). Its resolved value is stored as a durable `${credential.NAME}`. Ground each in the recording; don't invent them. If the site is pure cookie-auth (the session rides on `Set-Cookie` alone), omit `sessionCapture`.
|
|
52
|
-
|
|
53
|
-
## authConfig (structural — never a channel name)
|
|
54
|
-
|
|
55
|
-
Set `twoFactorType` to exactly one of:
|
|
56
|
-
- **`none`** — login completes in the initiate request(s); no second step.
|
|
57
|
-
- **`otp`** — a later request carries a short code the user got out-of-band (SMS, email, TOTP are all `otp`). Set `initiateRequestCount` (requests before that one run on `initiate`; the rest on `submit_otp`), declare an `otp_code` param, and if the completion reads a value the **initiate response returned** (e.g. a reauth `mfaId`), add a `capture` for it on the initiate request AND list its name in `twoFactorContext` (each call is stateless — this carries the token across the gap).
|
|
58
|
-
- **`push`** — one endpoint polled until its response flips (pending→approved) or a session cookie appears. Set `pollEndpoint` (+ optional `pollIntervalMs`/`maxPollAttempts`) and a `pollTerminal` capture grounded in the recorded **approved** poll (a field absent on the pending polls). Omit `pollTerminal` only to fall back to "a fresh session cookie appeared". **If the recorded poll request sends a body** (read it with `read_request` — many status endpoints require a JSON payload like `{"mfaId":"..."}` and reject an empty POST with 4xx), copy it into `pollBody` (templated: `${state.X}`/`${credential.X}`/`${param.X}`) and set `pollContentType` (and `pollMethod` if not POST) from the recorded request. A missing `pollBody` means the poll sends nothing, so an approval is never recognized.
|
|
59
|
-
|
|
60
|
-
## Replayable vs browser-minted logins
|
|
61
|
-
|
|
62
|
-
Auth runs on **cdp-replay** (a real headed browser): the verifier navigates `bootstrap.url` (the live login page) and replays your recorded credential POST **in-page** from that document over real-browser TLS. Read the credential POST with `read_request` and classify it:
|
|
63
|
-
- **Replayable** — plain form/JSON of username/password (+ static/capturable tokens). Replays directly.
|
|
64
|
-
- **Static signed/encrypted blob** — the body carries an encrypted credential blob / signature / public key the page computed at record time. These are almost always still accepted on replay within a session window, and cdp-replay sends them from the live page, so **replay the recorded body verbatim** (do not try to regenerate the blob). Capture any per-session token the *response* returns via `${state.X}` as usual.
|
|
65
|
-
- **Per-request nonce the server rejects on replay** — a value that must be minted by the page *for this exact POST* (a one-time WebCrypto challenge, a per-load reCAPTCHA token). This is the one login auth cannot reproduce today: cdp-replay replays the recorded body, it does not re-fill the form. Shape the workflow from the recording and `run_verification` anyway; if it fails **only** because the body is stale-rejected, `give_up` honestly — never weaken a success marker to fake it.
|
|
66
|
-
|
|
67
|
-
In all cases you emit **only `workflow.json`** for an authenticate tool. Do **not** write a `playbook.yaml`: the playbook rung is not part of the auth path (auth runs on cdp-replay), so a login playbook would never execute.
|
|
68
|
-
|
|
69
|
-
## Two rules that decide whether a 2FA login completes (read BEFORE writing captures)
|
|
70
|
-
|
|
71
|
-
These two patterns are the difference between a 2FA tool that works every run and one that breaks intermittently. Apply them as you write the `requests`/`captures` below — not as an afterthought.
|
|
72
|
-
|
|
73
|
-
1. **Capture from variable-order arrays by FIELD, not index.** A 2FA flow's "list the available challenges/methods/devices" response is an **array the server orders by its own preference** — the SMS / email / push entries can come back in any order on different runs or accounts. A fixed index (`challenges[0].…`) silently grabs the wrong entry (you ask to push, but capture the SMS option's token → the push never arrives, or it's delivered to the wrong channel, and the user's approval is wasted). **Select by a discriminator field instead:** `challenges[type=push].token` resolves to the FIRST array element whose `type` stringifies to `push`, regardless of position. Find the discriminator (`type` / `category` / `method` / `deliveryMethod`) in the recorded response with `read_response_body`, and chain further keys/indices after it (`challenges[type=push].options[0].token`). Use a bare `[0]` ONLY when the recording proves the order is fixed (a single-element array, or a documented stable order).
|
|
74
|
-
|
|
75
|
-
2. **Mark non-fatal steps `"optional": true`.** Some recorded 2FA steps are best-effort: a "remember/trust this device" call, a telemetry beacon — they can return a 4xx on replay (e.g. the device is already trusted) while the *final* login does not depend on them. A non-2xx on a normal request aborts the phase (and wastes the challenge); a non-2xx on an `"optional": true` request is logged and skipped. **Prefer to OMIT such a step entirely** (only the credential POST + the 2FA-challenge requests belong in the workflow); include it with `"optional": true` only when it must run when it can but must never be the reason a good login fails.
|
|
76
|
-
|
|
77
|
-
## workflow.json structure
|
|
1
|
+
# Auth compile agent
|
|
2
|
+
|
|
3
|
+
Compile the captured authentication recording into a deterministic
|
|
4
|
+
`workflow.json`, then prove the declared success path with live verification.
|
|
5
|
+
|
|
6
|
+
You decide the action boundaries, required inputs, evidence, carried state,
|
|
7
|
+
request repetition, error behavior, and completion criteria from the recording.
|
|
8
|
+
The runtime only executes the program you write.
|
|
9
|
+
|
|
10
|
+
## Process
|
|
11
|
+
|
|
12
|
+
1. Call `read_session_summary`.
|
|
13
|
+
2. Inspect relevant requests and responses with `search_requests`,
|
|
14
|
+
`read_request`, and `read_response_body`.
|
|
15
|
+
3. Write `workflow.json` and any recording-grounded
|
|
16
|
+
`request-transform.ts` needed by the requests.
|
|
17
|
+
4. Call `run_verification` with one declared action and its parameters, then
|
|
18
|
+
stop. The orchestrator runs it in a verification browser and resumes you with
|
|
19
|
+
the observed status, body preview, continuation, and next action.
|
|
20
|
+
5. Revise the artifact or continue through its actions. Use `prompt_user` only
|
|
21
|
+
when the program actually requires human input or an external user action.
|
|
22
|
+
When verification evidence warrants inspecting the existing browser page,
|
|
23
|
+
call `inspect_verification_page`; inspection never runs another auth action.
|
|
24
|
+
6. Call `done` only after a live action whose declared outcome is `success`
|
|
25
|
+
returns `ok: true`.
|
|
26
|
+
|
|
27
|
+
Live authentication happens only through `run_verification`. Do not contact the
|
|
28
|
+
site through shell commands or other tools.
|
|
29
|
+
|
|
30
|
+
Verification reuses one browser and continuation state by default. If an
|
|
31
|
+
observed result proves that state is no longer usable, you may set
|
|
32
|
+
`freshSession: true` on the next `run_verification`. This discards the prior
|
|
33
|
+
browser and continuation before running the requested action. Decide from live
|
|
34
|
+
evidence; do not encode site or authentication-channel assumptions.
|
|
35
|
+
Set `cleanSession: true` only when evidence also requires withholding stored
|
|
36
|
+
cookies and browser storage; credential values remain available.
|
|
37
|
+
|
|
38
|
+
## Auth program
|
|
39
|
+
|
|
40
|
+
Set `toolKind` to `"authenticate"`. Keep recorded network operations in the
|
|
41
|
+
ordinary top-level `requests` array. `authConfig` references those requests:
|
|
78
42
|
|
|
79
43
|
```json
|
|
80
44
|
{
|
|
81
|
-
"
|
|
82
|
-
"
|
|
83
|
-
|
|
84
|
-
|
|
85
|
-
|
|
86
|
-
|
|
87
|
-
|
|
88
|
-
|
|
89
|
-
|
|
90
|
-
|
|
91
|
-
|
|
92
|
-
|
|
93
|
-
|
|
94
|
-
|
|
95
|
-
|
|
96
|
-
|
|
97
|
-
|
|
98
|
-
"captures": [
|
|
99
|
-
{ "name": "pushToken", "source": "json", "path": "challenges[type=push].options[0].token" }
|
|
100
|
-
]
|
|
45
|
+
"entry": "agent_chosen_entry",
|
|
46
|
+
"actions": {
|
|
47
|
+
"agent_chosen_entry": {
|
|
48
|
+
"parameters": [],
|
|
49
|
+
"steps": [
|
|
50
|
+
{
|
|
51
|
+
"request": 0,
|
|
52
|
+
"onError": "fail"
|
|
53
|
+
}
|
|
54
|
+
],
|
|
55
|
+
"outcome": {
|
|
56
|
+
"type": "pause",
|
|
57
|
+
"next": "agent_chosen_next",
|
|
58
|
+
"evidence": ["recording_grounded_capture"],
|
|
59
|
+
"carry": ["state_needed_by_next_action"],
|
|
60
|
+
"message": "What the live result means for the caller"
|
|
61
|
+
}
|
|
101
62
|
},
|
|
102
|
-
|
|
103
|
-
|
|
104
|
-
|
|
105
|
-
|
|
106
|
-
|
|
107
|
-
|
|
108
|
-
|
|
109
|
-
|
|
110
|
-
|
|
111
|
-
|
|
112
|
-
|
|
113
|
-
|
|
114
|
-
|
|
115
|
-
|
|
116
|
-
|
|
117
|
-
|
|
118
|
-
|
|
63
|
+
"agent_chosen_next": {
|
|
64
|
+
"parameters": ["runtime_input_name"],
|
|
65
|
+
"steps": [
|
|
66
|
+
{
|
|
67
|
+
"request": 1,
|
|
68
|
+
"onError": "retry",
|
|
69
|
+
"repeat": {
|
|
70
|
+
"until": {
|
|
71
|
+
"source": "json",
|
|
72
|
+
"name": "recording_grounded_terminal",
|
|
73
|
+
"path": "recorded.path",
|
|
74
|
+
"equals": "recorded terminal value"
|
|
75
|
+
},
|
|
76
|
+
"intervalMs": 1000,
|
|
77
|
+
"maxAttempts": 30
|
|
78
|
+
}
|
|
79
|
+
}
|
|
80
|
+
],
|
|
81
|
+
"outcome": {
|
|
82
|
+
"type": "success",
|
|
83
|
+
"evidence": ["recording_grounded_terminal"]
|
|
84
|
+
}
|
|
85
|
+
}
|
|
86
|
+
},
|
|
87
|
+
"persist": [],
|
|
88
|
+
"crossOriginCookieReinjection": false
|
|
119
89
|
}
|
|
120
90
|
```
|
|
121
91
|
|
|
122
|
-
|
|
123
|
-
|
|
124
|
-
|
|
125
|
-
|
|
126
|
-
|
|
127
|
-
|
|
128
|
-
|
|
129
|
-
|
|
130
|
-
|
|
131
|
-
|
|
132
|
-
|
|
133
|
-
-
|
|
134
|
-
|
|
135
|
-
-
|
|
136
|
-
|
|
137
|
-
|
|
138
|
-
|
|
139
|
-
|
|
140
|
-
|
|
141
|
-
|
|
142
|
-
-
|
|
143
|
-
-
|
|
144
|
-
|
|
145
|
-
-
|
|
146
|
-
-
|
|
147
|
-
|
|
148
|
-
|
|
149
|
-
|
|
150
|
-
|
|
151
|
-
|
|
152
|
-
|
|
153
|
-
|
|
154
|
-
|
|
155
|
-
|
|
156
|
-
|
|
157
|
-
|
|
158
|
-
|
|
159
|
-
-
|
|
160
|
-
|
|
161
|
-
|
|
162
|
-
-
|
|
163
|
-
|
|
164
|
-
|
|
165
|
-
|
|
92
|
+
The names and values above are structural examples, not required names or auth
|
|
93
|
+
semantics.
|
|
94
|
+
|
|
95
|
+
- `entry` is the action used when no action parameter is supplied.
|
|
96
|
+
- Declare a top-level string workflow parameter named `action`; set its default
|
|
97
|
+
to `entry` and its `choices` to exactly the keys of `actions` so generated
|
|
98
|
+
tools expose every compiled action.
|
|
99
|
+
- `parameters` lists scalar workflow parameters required by that action.
|
|
100
|
+
- Each step references one entry in `requests`.
|
|
101
|
+
- `onError` is `fail`, `continue`, or `retry`. `retry` requires a
|
|
102
|
+
`repeat` block so the artifact supplies the bound.
|
|
103
|
+
- `repeat.until` is a normal request capture evaluated after each successful
|
|
104
|
+
response. The step repeats until it matches or reaches the declared bound.
|
|
105
|
+
- `evidence` optionally names captures that must exist before the outcome is
|
|
106
|
+
accepted. Empty strings, `false`, and `null` are valid when the capture
|
|
107
|
+
declares an exact `equals` value. Choose evidence from the recording when it
|
|
108
|
+
adds proof beyond successful execution of the declared steps.
|
|
109
|
+
- A `pause` outcome declares the next action, the exact state names to carry,
|
|
110
|
+
and the caller-facing message. Carry every prior capture referenced as
|
|
111
|
+
`${state.X}` by the next action unless that action produces it before use.
|
|
112
|
+
- A `success` outcome is the artifact's authentication completion criterion.
|
|
113
|
+
- `persist` names captured non-cookie values that data tools consume later as
|
|
114
|
+
`${credential.NAME}`. Cookies persist automatically.
|
|
115
|
+
- Set `crossOriginCookieReinjection` only when the recording proves a
|
|
116
|
+
cross-origin response cookie must be projected into the browser jar.
|
|
117
|
+
|
|
118
|
+
## Request construction
|
|
119
|
+
|
|
120
|
+
Use the standard workflow request schema: `method`, `url`, `headers`,
|
|
121
|
+
`recordingRequestSeq`, optional string `body`, optional `captures`, optional
|
|
122
|
+
`mode: "navigate"` with bounded navigation criteria, and optional `effect`.
|
|
123
|
+
Set `recordingRequestSeq` to the exact `seq` from `read_request` that grounds
|
|
124
|
+
the request. It is required on requests whose captures appear in
|
|
125
|
+
`authConfig.persist`, so `imprint login` extracts each value only from its
|
|
126
|
+
producing recorded response.
|
|
127
|
+
|
|
128
|
+
`mode: "navigate"` performs a real top-level browser navigation for GET and
|
|
129
|
+
`application/x-www-form-urlencoded` POST requests. Use it when the recording
|
|
130
|
+
shows a document form submission whose redirects or browser-owned state must be
|
|
131
|
+
preserved. Its response exposes the browser's final URL in the synthetic
|
|
132
|
+
`x-imprint-final-url` response header. Capture that header with
|
|
133
|
+
`source: "response_header"` when a redirect URL carries state needed by a later
|
|
134
|
+
request.
|
|
135
|
+
|
|
136
|
+
Use runtime templates exactly as supported:
|
|
137
|
+
`${credential.X}`, `${param.X}`, `${state.X}`,
|
|
138
|
+
`${response[N].path}`, and `${generated.uuid|nonce|epoch_s|epoch_ms|iso8601}`.
|
|
139
|
+
|
|
140
|
+
Ground every request, capture, predicate, retry bound, navigation criterion, and
|
|
141
|
+
transform in the recording. Preserve functional headers and request encoding.
|
|
142
|
+
Do not store recorded secrets or one-time values as literals. When browser code
|
|
143
|
+
must mint coupled state, represent the recorded page navigation or write a
|
|
144
|
+
general request transform supported by live inputs; if you write
|
|
145
|
+
`request-transform.ts`, set the workflow's top-level `requestTransformModule`
|
|
146
|
+
to `"./request-transform.ts"`. Verification determines whether it works.
|
|
147
|
+
|
|
148
|
+
There is no auth playbook. Do not write, inspect, or depend on
|
|
149
|
+
`playbook.yaml`.
|
|
150
|
+
|
|
151
|
+
## Checkpoints
|
|
152
|
+
|
|
153
|
+
One checkpoint call ends the current turn. After `run_verification`,
|
|
154
|
+
`inspect_verification_page`, `prompt_user`, or `wait_for_cooldown`, stop and wait
|
|
155
|
+
for the orchestrator.
|
|
156
|
+
It will resume the same Claude or Codex session with the result.
|
|
@@ -8,7 +8,7 @@ You receive:
|
|
|
8
8
|
|
|
9
9
|
- `site`, `url`, `narration` — what the user was doing. When several captures were merged, `narration` includes `[Recording from <timestamp>] <url>` boundary lines marking where each capture begins (the same logical request may then appear once per capture, often with a different entity/token).
|
|
10
10
|
- `selectedTools[]` — the tools that WILL be compiled: `{ toolName, description, expectedOutput, requestSeqs, dependencySeqs, likelyParams }`. You must emit exactly one `perTool` entry for each.
|
|
11
|
-
- `sharedContext` — `{ loginRequestSeqs, credentialNames, tokenExtractionNotes, sharedHelperNotes,
|
|
11
|
+
- `sharedContext` — `{ loginRequestSeqs, credentialNames, tokenExtractionNotes, sharedHelperNotes, authRequestSeqs, authNotes }` from candidate detection.
|
|
12
12
|
- `ephemeralValues[]` — values that differed across two independent replays (highest-confidence signal for signing tokens / per-call state): `{ classification, originalSeq, location, producerSeq, producerPath, suggestedStateName }`. `browser_minted` with a high-entropy query-param `location` is the canonical sign of client-side URL signing → a `request-transform` module.
|
|
13
13
|
- `tokenContractHints[]` — producer→consumer opaque-token edges DETECTED DETERMINISTICALLY from the dual-pass diff: `{ consumerTool, consumerParam, consumerLocation, producerTool, producerField, producerPath }`. Each is a grounded `server_derived` value `consumerTool` sends that was produced in `producerTool`'s response. These are pre-computed for you and are AUTHORITATIVE — you MUST declare each as a `tokenParams` (consumer) + `emitsTokens` (producer) contract per rule 12. Refine the rough `consumerParam`/`producerField` names and the `shape` from the recording, but do not drop an edge. (Any edge you miss is reconciled in deterministically, but declaring it yourself lets you pick the right `shape`.)
|
|
14
14
|
- `requiredInputHints[]` — the GENERAL dependency contract DETECTED DETERMINISTICALLY from the recording: `{ consumerTool, input: { location, source, wiring, ... }, authCapture? }`. Each `input` is one thing a tool's request needs and where it comes from — `auth` (a login-minted session token → `${credential.X}`), `producer_tool` (a sibling token → param), `browser_state` (a captured `${state.X}` or, for a `referer` location, a `bootstrap.url`), `generated` (a per-call `${generated.uuid|epoch_ms|epoch_s|iso8601|nonce}`), or `static` (a page-minted app constant emitted verbatim). These are AUTHORITATIVE — copy each into the owning tool's `requiredInputs[]` (rule 13). For an `auth` input, also ensure `authTool.captures` carries its `authCapture` so the login persists it. Any input you drop is reconciled in deterministically, but declaring it yourself lets you refine the name/notes.
|
|
@@ -40,17 +40,15 @@ You receive:
|
|
|
40
40
|
"sourceSeqs": [number]
|
|
41
41
|
}
|
|
42
42
|
],
|
|
43
|
-
"authTool": { // OPTIONAL — whenever
|
|
43
|
+
"authTool": { // OPTIONAL — whenever sharedContext contains authentication requests
|
|
44
44
|
"toolName": "authenticate_<site>",
|
|
45
|
-
"
|
|
46
|
-
"
|
|
47
|
-
"twoFactorType": "none" | "otp" | "push", // structural: none = login completes in the login request(s); otp = code typed back; push = poll until approved
|
|
48
|
-
"twoFactorContext": [string], // otp only: initiate-response fields the submit_otp request chains via ${state.X}
|
|
45
|
+
"credentialRequestSeqs": [number],
|
|
46
|
+
"authRequestSeqs": [number],
|
|
49
47
|
"credentialNames": ["username", "password"],
|
|
50
48
|
"captures": [
|
|
51
49
|
{ "name": "session_cookie", "source": "cookie", "locator": "cookie_name", "usedAs": "cookie" }
|
|
52
50
|
],
|
|
53
|
-
"notes": "
|
|
51
|
+
"notes": "recorded auth request/response relationships; the auth compile agent decides actions"
|
|
54
52
|
},
|
|
55
53
|
"perTool": [
|
|
56
54
|
{
|
|
@@ -89,10 +87,17 @@ You receive:
|
|
|
89
87
|
|
|
90
88
|
1. **Emit exactly one `perTool` entry per `selectedTools` entry**, using the same `toolName`. Do not invent or drop tools.
|
|
91
89
|
2. **Only hoist a shared module when ≥2 selected tools genuinely share it.** Single-use logic stays inside that tool's own parser.ts / request-transform.ts — do NOT create a `_shared/` module for it.
|
|
92
|
-
3. **`request-transform`** — URL signing or body construction shared across tools. Wire-up: the consuming tool sets `requestTransformModule: "../_shared/<name>.ts"`. Ground it in `ephemeralValues` (browser_minted, high-entropy query param) and `sourceSeqs`. The exported `transform(method, url, responses, params?)` returns the signed URL (or `{ url
|
|
90
|
+
3. **`request-transform`** — URL signing or body construction shared across tools. Wire-up: the consuming tool sets `requestTransformModule: "../_shared/<name>.ts"`. Ground it in `ephemeralValues` (browser_minted, high-entropy query param) and `sourceSeqs`. The exported `transform(method, url, responses, params?)` returns the signed URL (or `{ url?, body?, headers?, skip? }`).
|
|
93
91
|
4. **`parser-helper`** — a decoder/normalizer ≥2 tools' parsers call (e.g. a shared JSPB walker, a shared field mapper). The consuming tool's parser.ts does `import { ... } from '../_shared/<name>.ts'`. Ground it in a captured response body (`sourceSeqs`).
|
|
94
92
|
5. **`types`** — shared TypeScript interfaces used by ≥2 parsers. Type-only; no runtime behavior.
|
|
95
|
-
6. **Auth is NEVER a shared module.**
|
|
93
|
+
6. **Auth is NEVER a shared module.** When `sharedContext.authRequestSeqs` or
|
|
94
|
+
`loginRequestSeqs` is non-empty, declare one standalone
|
|
95
|
+
`authenticate_<site>` tool. Copy credential-bearing requests to
|
|
96
|
+
`credentialRequestSeqs` and all related auth requests to `authRequestSeqs`.
|
|
97
|
+
Do not prescribe phases or action boundaries; the auth compile agent derives
|
|
98
|
+
them from the recording. Data tools set `authRecipe.required: false` and
|
|
99
|
+
`dependsOnAuth: true` so they reuse the stored session. `credentialNames`
|
|
100
|
+
contains durable provisioned values only, never live one-time input.
|
|
96
101
|
7. **`exportSignatures` must be real TypeScript signatures** the builder will implement and the verifier will check for. List every public export.
|
|
97
102
|
8. **`spec` must be concrete enough to implement and test** — name the inputs, the exact output, and the `sourceSeqs` that prove it (e.g. "given the URL at seq 41 with the `sig` param stripped, regenerate `sig` to match the recorded value").
|
|
98
103
|
9. **`dependsOn` only references other `sharedModules[].path`.** No cycles.
|
|
@@ -10,12 +10,8 @@ Schema:
|
|
|
10
10
|
"credentialNames": [string],
|
|
11
11
|
"tokenExtractionNotes": "string",
|
|
12
12
|
"sharedHelperNotes": "string",
|
|
13
|
-
"
|
|
14
|
-
"
|
|
15
|
-
"twoFactorRequestSeqs": [number],
|
|
16
|
-
"authCompletionSeqs": [number],
|
|
17
|
-
"twoFactorContext": [string],
|
|
18
|
-
"twoFactorNotes": "string"
|
|
13
|
+
"authRequestSeqs": [number],
|
|
14
|
+
"authNotes": "string"
|
|
19
15
|
},
|
|
20
16
|
"candidates": [
|
|
21
17
|
{
|
|
@@ -44,29 +40,13 @@ Rules:
|
|
|
44
40
|
2. Do not expose login, auth, CSRF refresh, telemetry, page bootstrap, or
|
|
45
41
|
tracking as tools. Put login/auth request seqs in sharedContext.loginRequestSeqs
|
|
46
42
|
or candidate.dependencySeqs instead.
|
|
47
|
-
3.
|
|
48
|
-
|
|
49
|
-
|
|
50
|
-
|
|
51
|
-
|
|
52
|
-
|
|
53
|
-
|
|
54
|
-
value the *initiate response returned in its body* (e.g. a reauth `mfaId`),
|
|
55
|
-
list the field name(s) in `twoFactorContext` so the compiler chains them.
|
|
56
|
-
- **`push`** — the same endpoint is polled repeatedly until its response flips
|
|
57
|
-
(pending→approved) or a session cookie appears; no code re-enters the flow.
|
|
58
|
-
In `twoFactorNotes`, name the poll endpoint and the field/value that marks
|
|
59
|
-
approval in the recorded terminal poll.
|
|
60
|
-
Put the 2FA-related request seqs in `twoFactorRequestSeqs`; post-2FA
|
|
61
|
-
finalization requests (trusted device registration, final OAuth exchange,
|
|
62
|
-
session confirmation) in `authCompletionSeqs`. These seqs must NOT appear
|
|
63
|
-
in any candidate's `requestSeqs` — they belong to the auth flow, not data
|
|
64
|
-
tools. When no 2FA is detected, set `twoFactorDetected: false` and leave
|
|
65
|
-
the other fields at defaults. `credentialNames` lists ONLY the durable login
|
|
66
|
-
secrets the user provisions once — the `${credential.*}` fields submitted in
|
|
67
|
-
the login request(s), typically `username` + `password`. NEVER put the live
|
|
68
|
-
one-time 2FA code in `credentialNames`: it is captured by
|
|
69
|
-
`twoFactorType`/`twoFactorContext` and entered fresh at runtime, not stored.
|
|
43
|
+
3. Put every request that belongs to authentication in `authRequestSeqs`,
|
|
44
|
+
including credential submission, user-interaction checkpoints, repeated
|
|
45
|
+
status checks, redirects, exchanges, and finalization. Describe only the
|
|
46
|
+
observed request/response relationships in `authNotes`; do not classify the
|
|
47
|
+
flow into runtime phases. The auth compile agent will derive its action graph
|
|
48
|
+
from the recording. `credentialNames` lists only durable login values the
|
|
49
|
+
user provisions, never live one-time input.
|
|
70
50
|
4. When multiple requests contain `${credential.*}` placeholders (multiple
|
|
71
51
|
login attempts in the recording), check each request's `status` and
|
|
72
52
|
`responsePreview` to determine which attempt(s) actually succeeded. A
|