imprint-mcp 0.7.0 → 0.7.2
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 +66 -2
- package/package.json +1 -1
- package/prompts/auth-compile-agent.md +173 -22
- package/prompts/compile-agent.md +45 -8
- package/prompts/component-recovery.md +40 -0
- package/prompts/master-teach-decision.md +28 -3
- package/prompts/master-teach-focused-planner.md +18 -5
- package/src/cli.ts +26 -18
- package/src/imprint/agent-tool.ts +15 -0
- package/src/imprint/agent.ts +2 -11
- package/src/imprint/audit.ts +35 -13
- package/src/imprint/auth-browser-discovery.ts +276 -0
- package/src/imprint/auth-compile-agent.ts +513 -224
- package/src/imprint/auth-compile-tools.ts +213 -25
- package/src/imprint/auth-discovery-evidence.ts +81 -0
- package/src/imprint/auth-plan.ts +28 -0
- package/src/imprint/auth-verifier.ts +234 -20
- package/src/imprint/authentication-interaction.ts +137 -0
- package/src/imprint/backend-ladder.ts +271 -43
- package/src/imprint/build-plan.ts +2 -22
- package/src/imprint/cdp-browser-fetch.ts +242 -60
- package/src/imprint/chromium.ts +93 -29
- package/src/imprint/claude-cli-compile.ts +2 -0
- package/src/imprint/codex-cli-compile.ts +99 -46
- package/src/imprint/compile-agent-types.ts +9 -5
- package/src/imprint/compile-agent.ts +33 -0
- package/src/imprint/compile-tool-executor.ts +783 -0
- package/src/imprint/compile-tools.ts +42 -9
- package/src/imprint/compile-verification.ts +2 -0
- package/src/imprint/compile.ts +3 -0
- package/src/imprint/compiler-log.ts +16 -0
- package/src/imprint/component-recovery.ts +120 -0
- package/src/imprint/cookie-jar.ts +117 -7
- package/src/imprint/credential-extract.ts +9 -2
- package/src/imprint/credential-lock.ts +147 -0
- package/src/imprint/credential-observation.ts +261 -0
- package/src/imprint/credential-store.ts +284 -44
- package/src/imprint/live-component-recovery.ts +73 -0
- package/src/imprint/llm.ts +4 -3
- package/src/imprint/log.ts +16 -1
- package/src/imprint/login.ts +9 -0
- package/src/imprint/master-teach-agent-contracts.ts +40 -3
- package/src/imprint/master-teach-agents.ts +229 -14
- package/src/imprint/master-teach-checks.ts +8 -1
- package/src/imprint/master-teach-controller.ts +681 -138
- package/src/imprint/master-teach-prompt-projections.ts +2 -0
- package/src/imprint/mcp-cdp-sessions.ts +7 -2
- package/src/imprint/mcp-compile-server.ts +62 -850
- package/src/imprint/mcp-server.ts +667 -91
- package/src/imprint/mcp-session-recovery.ts +167 -0
- package/src/imprint/native-teach-agents.ts +232 -108
- package/src/imprint/runtime.ts +416 -47
- package/src/imprint/stealth-chromium.ts +67 -7
- package/src/imprint/teach-browser-resources.ts +88 -0
- package/src/imprint/teach-stage-progress.ts +38 -0
- package/src/imprint/terminal-user-prompt.ts +42 -0
- package/src/imprint/types.ts +51 -18
- package/src/imprint/user-interaction.ts +836 -0
|
@@ -7,7 +7,10 @@
|
|
|
7
7
|
import { createHash } from 'node:crypto';
|
|
8
8
|
import { existsSync, readFileSync } from 'node:fs';
|
|
9
9
|
import { join as pathJoin } from 'node:path';
|
|
10
|
+
import { z } from 'zod';
|
|
10
11
|
import type { AgentTool } from './agent.ts';
|
|
12
|
+
import { AuthBrowserActionSchema } from './auth-browser-discovery.ts';
|
|
13
|
+
import type { AuthCheckpoint, AuthCheckpointResult } from './compile-agent-types.ts';
|
|
11
14
|
import {
|
|
12
15
|
type CompileToolContext,
|
|
13
16
|
bodyEncodingContractFailures,
|
|
@@ -24,7 +27,13 @@ import {
|
|
|
24
27
|
import { isIrreversibleRequest, workflowHasIrreversibleEffect } from './effects.ts';
|
|
25
28
|
import { recordedRequestMatchesWorkflow } from './recording-request.ts';
|
|
26
29
|
import { captureHeader, captureValueMatches, resolveJsonCapture } from './request-capture.ts';
|
|
27
|
-
import {
|
|
30
|
+
import {
|
|
31
|
+
type Session,
|
|
32
|
+
type Workflow,
|
|
33
|
+
WorkflowSchema,
|
|
34
|
+
authActionOutcomes,
|
|
35
|
+
persistedCaptureName,
|
|
36
|
+
} from './types.ts';
|
|
28
37
|
|
|
29
38
|
type TeachCredentials = { site: string; values: Record<string, string> };
|
|
30
39
|
|
|
@@ -32,9 +41,15 @@ export const AUTH_VERIFICATION_ATTEMPT_SENTINEL = '.auth-verification-attempt.js
|
|
|
32
41
|
|
|
33
42
|
export interface AuthCliCompileMode {
|
|
34
43
|
site: string;
|
|
44
|
+
contextRef?: string;
|
|
35
45
|
authPlanJson: string;
|
|
36
46
|
allowedTools: readonly string[];
|
|
37
47
|
initialPrompt: string;
|
|
48
|
+
/** Host-only native/API execution; CLI-only drivers retain the sentinel fallback. */
|
|
49
|
+
executeCheckpoint?: (
|
|
50
|
+
checkpoint: AuthCheckpoint,
|
|
51
|
+
signal?: AbortSignal,
|
|
52
|
+
) => Promise<AuthCheckpointResult>;
|
|
38
53
|
}
|
|
39
54
|
|
|
40
55
|
export const AUTH_COMPILE_TOOL_NAMES = [
|
|
@@ -47,10 +62,165 @@ export const AUTH_COMPILE_TOOL_NAMES = [
|
|
|
47
62
|
'run_tests',
|
|
48
63
|
'run_verification',
|
|
49
64
|
'inspect_verification_page',
|
|
65
|
+
'interact_verification_browser',
|
|
50
66
|
'prompt_user',
|
|
51
67
|
'wait_for_cooldown',
|
|
52
68
|
] as const;
|
|
53
69
|
|
|
70
|
+
export const AUTH_CHECKPOINT_TOOLS: Omit<AgentTool, 'handler'>[] = [
|
|
71
|
+
{
|
|
72
|
+
name: 'interact_verification_browser',
|
|
73
|
+
description:
|
|
74
|
+
'Explore the live auth UI in the retained verification browser and capture its network requests/responses as additional readable recording evidence. Can open a browser before a workflow exists. Choose inspect, navigate, click, fill, select, press, or wait from observed page controls. For fill values use stored ${credential.NAME} or current ${prompt.ID} references; answers are resolved locally. Capture continues between calls and while prompting the human. This does not verify the compiled workflow.',
|
|
75
|
+
input_schema: {
|
|
76
|
+
type: 'object',
|
|
77
|
+
properties: {
|
|
78
|
+
action: {
|
|
79
|
+
type: 'string',
|
|
80
|
+
enum: ['inspect', 'navigate', 'click', 'fill', 'select', 'press', 'wait'],
|
|
81
|
+
},
|
|
82
|
+
url: { type: 'string', description: 'HTTP(S) destination for navigate.' },
|
|
83
|
+
selector: {
|
|
84
|
+
type: 'string',
|
|
85
|
+
description: 'Exact CSS selector from the observed UI for click/fill/select.',
|
|
86
|
+
},
|
|
87
|
+
value: {
|
|
88
|
+
type: 'string',
|
|
89
|
+
description:
|
|
90
|
+
'Value for fill/select; secret inputs use credential or current prompt references.',
|
|
91
|
+
},
|
|
92
|
+
key: { type: 'string', description: 'Keyboard key for press, e.g. Enter or Tab.' },
|
|
93
|
+
milliseconds: { type: 'number', description: 'Observation wait duration, 0–30000 ms.' },
|
|
94
|
+
},
|
|
95
|
+
required: ['action'],
|
|
96
|
+
},
|
|
97
|
+
},
|
|
98
|
+
{
|
|
99
|
+
name: 'run_verification',
|
|
100
|
+
description:
|
|
101
|
+
'Run one action from the current workflow.json live in the verification browser. First reuse the proven noninteractive session-check or context-restoration action before restarting login. Branch on current response evidence before delivering MFA. Supply the action name and only its declared parameters. Set freshSession only when observed evidence means the prior browser and continuation state must be discarded. Set cleanSession only when evidence requires also withholding stored cookies and browser storage.',
|
|
102
|
+
input_schema: {
|
|
103
|
+
type: 'object',
|
|
104
|
+
properties: {
|
|
105
|
+
action: {
|
|
106
|
+
type: 'string',
|
|
107
|
+
description: 'An action declared in authConfig.actions.',
|
|
108
|
+
},
|
|
109
|
+
parameters: {
|
|
110
|
+
type: 'object',
|
|
111
|
+
description: 'Scalar values required by this action, keyed by workflow parameter name.',
|
|
112
|
+
},
|
|
113
|
+
freshSession: {
|
|
114
|
+
type: 'boolean',
|
|
115
|
+
description:
|
|
116
|
+
'Close and discard the prior verification browser and continuation state before running this action. Defaults to false.',
|
|
117
|
+
},
|
|
118
|
+
cleanSession: {
|
|
119
|
+
type: 'boolean',
|
|
120
|
+
description:
|
|
121
|
+
'Also withhold stored cookies and browser storage for this fresh run. Credential values remain available.',
|
|
122
|
+
},
|
|
123
|
+
},
|
|
124
|
+
required: ['action'],
|
|
125
|
+
},
|
|
126
|
+
},
|
|
127
|
+
{
|
|
128
|
+
name: 'inspect_verification_page',
|
|
129
|
+
description:
|
|
130
|
+
'Inspect the currently rendered page in the existing verification browser without navigating, resetting state, or running another auth action. Returns rendered body text, final URL, title, and optional cookies. Known user-supplied secrets are masked; other cookie values remain private evidence. Use when observed verification evidence warrants inspecting the page.',
|
|
131
|
+
input_schema: {
|
|
132
|
+
type: 'object',
|
|
133
|
+
properties: {
|
|
134
|
+
maxChars: {
|
|
135
|
+
type: 'number',
|
|
136
|
+
description: 'Maximum rendered body-text characters to return (256–20000).',
|
|
137
|
+
},
|
|
138
|
+
includeCookies: {
|
|
139
|
+
type: 'boolean',
|
|
140
|
+
description:
|
|
141
|
+
'Include cookies with names, values, domains, paths, expirations, and flags. Known user-supplied secrets are masked. Defaults to true.',
|
|
142
|
+
},
|
|
143
|
+
},
|
|
144
|
+
},
|
|
145
|
+
},
|
|
146
|
+
{
|
|
147
|
+
name: 'prompt_user',
|
|
148
|
+
description:
|
|
149
|
+
'Ask the human for input or an external action required by the compiled auth program. A selected fixed option is returned as an answered choice with its exact value; free-text answers remain current opaque response references. A choice is not proof that a live action succeeded.',
|
|
150
|
+
input_schema: {
|
|
151
|
+
type: 'object',
|
|
152
|
+
properties: {
|
|
153
|
+
message: { type: 'string', description: 'What to ask the user to do.' },
|
|
154
|
+
options: {
|
|
155
|
+
type: 'array',
|
|
156
|
+
items: { type: 'string' },
|
|
157
|
+
description: 'Optional fixed choices; omit for free-text (e.g. the OTP code).',
|
|
158
|
+
},
|
|
159
|
+
},
|
|
160
|
+
required: ['message'],
|
|
161
|
+
},
|
|
162
|
+
},
|
|
163
|
+
{
|
|
164
|
+
name: 'wait_for_cooldown',
|
|
165
|
+
description:
|
|
166
|
+
'Request a delay without running any live action. Use only when the observed site response justifies waiting.',
|
|
167
|
+
input_schema: {
|
|
168
|
+
type: 'object',
|
|
169
|
+
properties: {
|
|
170
|
+
minutes: { type: 'number', description: 'Cool-off minutes (5–10 typical).' },
|
|
171
|
+
reason: {
|
|
172
|
+
type: 'string',
|
|
173
|
+
description: 'Why you believe it is a cool-off, not a defect.',
|
|
174
|
+
},
|
|
175
|
+
},
|
|
176
|
+
required: ['minutes'],
|
|
177
|
+
},
|
|
178
|
+
},
|
|
179
|
+
];
|
|
180
|
+
|
|
181
|
+
/** Parse the same host request for inline and checkpoint/resume adapters. */
|
|
182
|
+
export function parseAuthCheckpoint(name: string, input: unknown): AuthCheckpoint {
|
|
183
|
+
switch (name) {
|
|
184
|
+
case 'interact_verification_browser':
|
|
185
|
+
return { kind: name, ...AuthBrowserActionSchema.parse(input) };
|
|
186
|
+
case 'run_verification':
|
|
187
|
+
return {
|
|
188
|
+
kind: name,
|
|
189
|
+
...z
|
|
190
|
+
.object({
|
|
191
|
+
action: z.string().min(1),
|
|
192
|
+
parameters: z.record(z.union([z.string(), z.number(), z.boolean()])).optional(),
|
|
193
|
+
freshSession: z.boolean().optional(),
|
|
194
|
+
cleanSession: z.boolean().optional(),
|
|
195
|
+
})
|
|
196
|
+
.parse(input),
|
|
197
|
+
};
|
|
198
|
+
case 'inspect_verification_page':
|
|
199
|
+
return {
|
|
200
|
+
kind: name,
|
|
201
|
+
...z
|
|
202
|
+
.object({ maxChars: z.number().optional(), includeCookies: z.boolean().optional() })
|
|
203
|
+
.parse(input),
|
|
204
|
+
};
|
|
205
|
+
case 'prompt_user':
|
|
206
|
+
return {
|
|
207
|
+
kind: name,
|
|
208
|
+
...z
|
|
209
|
+
.object({ message: z.string().min(1), options: z.array(z.string()).optional() })
|
|
210
|
+
.parse(input),
|
|
211
|
+
};
|
|
212
|
+
case 'wait_for_cooldown':
|
|
213
|
+
return {
|
|
214
|
+
kind: name,
|
|
215
|
+
...z
|
|
216
|
+
.object({ minutes: z.number().nonnegative(), reason: z.string().optional() })
|
|
217
|
+
.parse(input),
|
|
218
|
+
};
|
|
219
|
+
default:
|
|
220
|
+
throw new Error(`Unknown auth checkpoint: ${name}`);
|
|
221
|
+
}
|
|
222
|
+
}
|
|
223
|
+
|
|
54
224
|
export function buildAuthCompileTools(
|
|
55
225
|
session: Session,
|
|
56
226
|
toolDir: string,
|
|
@@ -295,6 +465,18 @@ function authProgramFailures(
|
|
|
295
465
|
}
|
|
296
466
|
}
|
|
297
467
|
}
|
|
468
|
+
for (const branch of action.branches ?? []) {
|
|
469
|
+
const capture = branch.when;
|
|
470
|
+
if (captures.has(capture.name)) {
|
|
471
|
+
failures.push(
|
|
472
|
+
`capture name ${JSON.stringify(capture.name)} must be unique across the auth workflow`,
|
|
473
|
+
);
|
|
474
|
+
}
|
|
475
|
+
captures.add(capture.name);
|
|
476
|
+
const lastStep = action.steps.at(-1);
|
|
477
|
+
const request = lastStep && workflow.requests[lastStep.request];
|
|
478
|
+
if (request) captureOwners.set(capture.name, { request, capture });
|
|
479
|
+
}
|
|
298
480
|
}
|
|
299
481
|
|
|
300
482
|
let hasSuccess = false;
|
|
@@ -318,28 +500,30 @@ function authProgramFailures(
|
|
|
318
500
|
);
|
|
319
501
|
}
|
|
320
502
|
}
|
|
321
|
-
for (const
|
|
322
|
-
|
|
323
|
-
|
|
324
|
-
|
|
325
|
-
|
|
326
|
-
|
|
327
|
-
|
|
328
|
-
if (action.outcome.type === 'pause') {
|
|
329
|
-
if (!config.actions[action.outcome.next]) {
|
|
330
|
-
failures.push(
|
|
331
|
-
`action ${JSON.stringify(name)} pauses to unknown action ${JSON.stringify(action.outcome.next)}`,
|
|
332
|
-
);
|
|
503
|
+
for (const outcome of authActionOutcomes(action)) {
|
|
504
|
+
for (const evidence of outcome.evidence) {
|
|
505
|
+
if (!captures.has(evidence)) {
|
|
506
|
+
failures.push(
|
|
507
|
+
`action ${JSON.stringify(name)} references unknown evidence capture ${JSON.stringify(evidence)}`,
|
|
508
|
+
);
|
|
509
|
+
}
|
|
333
510
|
}
|
|
334
|
-
|
|
335
|
-
if (!
|
|
511
|
+
if (outcome.type === 'pause') {
|
|
512
|
+
if (!config.actions[outcome.next]) {
|
|
336
513
|
failures.push(
|
|
337
|
-
`action ${JSON.stringify(name)}
|
|
514
|
+
`action ${JSON.stringify(name)} pauses to unknown action ${JSON.stringify(outcome.next)}`,
|
|
338
515
|
);
|
|
339
516
|
}
|
|
517
|
+
for (const carried of outcome.carry) {
|
|
518
|
+
if (!captures.has(carried)) {
|
|
519
|
+
failures.push(
|
|
520
|
+
`action ${JSON.stringify(name)} carries unknown capture ${JSON.stringify(carried)}`,
|
|
521
|
+
);
|
|
522
|
+
}
|
|
523
|
+
}
|
|
524
|
+
} else {
|
|
525
|
+
hasSuccess = true;
|
|
340
526
|
}
|
|
341
|
-
} else {
|
|
342
|
-
hasSuccess = true;
|
|
343
527
|
}
|
|
344
528
|
}
|
|
345
529
|
|
|
@@ -428,13 +612,17 @@ function reachableSuccess(
|
|
|
428
612
|
actions: NonNullable<Workflow['authConfig']>['actions'],
|
|
429
613
|
): boolean {
|
|
430
614
|
const seen = new Set<string>();
|
|
431
|
-
|
|
432
|
-
while (
|
|
615
|
+
const pending = [entry];
|
|
616
|
+
while (pending.length) {
|
|
617
|
+
const current = pending.pop();
|
|
618
|
+
if (!current || seen.has(current)) continue;
|
|
433
619
|
seen.add(current);
|
|
434
|
-
const action
|
|
435
|
-
if (!action)
|
|
436
|
-
|
|
437
|
-
|
|
620
|
+
const action = actions[current];
|
|
621
|
+
if (!action) continue;
|
|
622
|
+
for (const outcome of authActionOutcomes(action)) {
|
|
623
|
+
if (outcome.type === 'success') return true;
|
|
624
|
+
pending.push(outcome.next);
|
|
625
|
+
}
|
|
438
626
|
}
|
|
439
627
|
return false;
|
|
440
628
|
}
|
|
@@ -501,7 +689,7 @@ export function readAuthVerificationReceiptStatus(
|
|
|
501
689
|
};
|
|
502
690
|
}
|
|
503
691
|
const action = workflow.authConfig?.actions[attempt.action];
|
|
504
|
-
if (action
|
|
692
|
+
if (!action || !authActionOutcomes(action).some((outcome) => outcome.type === 'success')) {
|
|
505
693
|
return {
|
|
506
694
|
status: 'failed',
|
|
507
695
|
reason: `the most recent successful live action ${JSON.stringify(attempt.action)} does not declare a success outcome`,
|
|
@@ -0,0 +1,81 @@
|
|
|
1
|
+
import { join } from 'node:path';
|
|
2
|
+
import type { AuthBrowserObservation } from './auth-browser-discovery.ts';
|
|
3
|
+
import { writePrivateFile } from './private-file.ts';
|
|
4
|
+
import type { Session } from './types.ts';
|
|
5
|
+
|
|
6
|
+
/** A run-local working copy. Original demonstrations are never overwritten.
|
|
7
|
+
* Live requests use the ordinary recording readers/tests and provenance fields. */
|
|
8
|
+
export class AuthDiscoveryEvidence {
|
|
9
|
+
readonly session: Session;
|
|
10
|
+
readonly sessionPath: string;
|
|
11
|
+
private readonly identities = new Map<string, number>();
|
|
12
|
+
private nextSeq: number;
|
|
13
|
+
|
|
14
|
+
constructor(
|
|
15
|
+
session: Session,
|
|
16
|
+
private readonly toolDir: string,
|
|
17
|
+
) {
|
|
18
|
+
this.session = structuredClone(session);
|
|
19
|
+
this.nextSeq = Math.max(-1, ...session.requests.map((r) => r.seq)) + 1;
|
|
20
|
+
this.sessionPath = join(toolDir, '.auth-evidence-session.json');
|
|
21
|
+
this.save();
|
|
22
|
+
}
|
|
23
|
+
|
|
24
|
+
append(observation: AuthBrowserObservation): string {
|
|
25
|
+
const observedAt = new Date().toISOString();
|
|
26
|
+
const timestamp = Date.now() - Date.parse(this.session.startedAt);
|
|
27
|
+
const index = observation.requests.map((request) => {
|
|
28
|
+
const identity = `${observation.sourceId}:${request.seq}`;
|
|
29
|
+
let seq = this.identities.get(identity);
|
|
30
|
+
if (seq === undefined) {
|
|
31
|
+
seq = this.nextSeq++;
|
|
32
|
+
this.identities.set(identity, seq);
|
|
33
|
+
}
|
|
34
|
+
const prior = this.session.requests.findIndex((r) => r.seq === seq);
|
|
35
|
+
const captured = {
|
|
36
|
+
...request,
|
|
37
|
+
seq,
|
|
38
|
+
timestamp: this.session.requests[prior]?.timestamp ?? timestamp,
|
|
39
|
+
};
|
|
40
|
+
if (prior < 0) this.session.requests.push(captured);
|
|
41
|
+
else this.session.requests[prior] = captured;
|
|
42
|
+
return {
|
|
43
|
+
seq,
|
|
44
|
+
method: captured.method,
|
|
45
|
+
url: captured.url,
|
|
46
|
+
status: captured.response?.status,
|
|
47
|
+
hasResponseBody: captured.response?.body !== undefined,
|
|
48
|
+
};
|
|
49
|
+
});
|
|
50
|
+
this.save();
|
|
51
|
+
writePrivateFile(
|
|
52
|
+
join(this.toolDir, '.auth-live-discovery.json'),
|
|
53
|
+
JSON.stringify(
|
|
54
|
+
{
|
|
55
|
+
observedAt,
|
|
56
|
+
identities: Object.fromEntries(this.identities),
|
|
57
|
+
sessionPath: this.sessionPath,
|
|
58
|
+
note: 'Appended live browser observations are separate demonstrations; replay must obtain fresh state.',
|
|
59
|
+
},
|
|
60
|
+
null,
|
|
61
|
+
2,
|
|
62
|
+
),
|
|
63
|
+
);
|
|
64
|
+
return JSON.stringify({
|
|
65
|
+
observedAt,
|
|
66
|
+
page: observation.page,
|
|
67
|
+
capturedRequests: index,
|
|
68
|
+
captureErrors: observation.captureErrors.map((error) => ({
|
|
69
|
+
...error,
|
|
70
|
+
seq: this.identities.get(`${observation.sourceId}:${error.seq}`),
|
|
71
|
+
})),
|
|
72
|
+
evidenceSessionPath: this.sessionPath,
|
|
73
|
+
guidance:
|
|
74
|
+
'Read captured requests/responses with the recording tools and cite their seq as recordingRequestSeq. IMPRINT_SESSION_PATH now includes this evidence. Discovery is not compiled replay verification.',
|
|
75
|
+
});
|
|
76
|
+
}
|
|
77
|
+
|
|
78
|
+
private save(): void {
|
|
79
|
+
writePrivateFile(this.sessionPath, JSON.stringify(this.session));
|
|
80
|
+
}
|
|
81
|
+
}
|
|
@@ -0,0 +1,28 @@
|
|
|
1
|
+
/** Recording-grounded authentication plan shared by agent interfaces. */
|
|
2
|
+
import { z } from 'zod';
|
|
3
|
+
|
|
4
|
+
export const AuthCaptureSchema = z.object({
|
|
5
|
+
name: z.string().min(1),
|
|
6
|
+
/** Capture source: json | response_header | cookie | text_regex. */
|
|
7
|
+
source: z.string().min(1),
|
|
8
|
+
/** Path / header name / cookie name / regex that locates the value. */
|
|
9
|
+
locator: z.string().min(1),
|
|
10
|
+
/** Where the captured value is injected downstream, e.g. "header:Authorization". */
|
|
11
|
+
usedAs: z.string().default(''),
|
|
12
|
+
});
|
|
13
|
+
|
|
14
|
+
export const AuthToolPlanSchema = z
|
|
15
|
+
.object({
|
|
16
|
+
toolName: z.string(),
|
|
17
|
+
/** Explicit model-selected retained context; omitted preserves legacy label reuse. */
|
|
18
|
+
contextRef: z.string().min(1).optional(),
|
|
19
|
+
/** Deliberately isolated context; mutually exclusive with contextRef. */
|
|
20
|
+
newContext: z.boolean().optional(),
|
|
21
|
+
credentialRequestSeqs: z.array(z.number().int().nonnegative()).default([]),
|
|
22
|
+
authRequestSeqs: z.array(z.number().int().nonnegative()).default([]),
|
|
23
|
+
credentialNames: z.array(z.string()).default([]),
|
|
24
|
+
captures: z.array(AuthCaptureSchema).default([]),
|
|
25
|
+
notes: z.string().default(''),
|
|
26
|
+
})
|
|
27
|
+
.optional();
|
|
28
|
+
export type AuthToolPlan = z.infer<typeof AuthToolPlanSchema>;
|