@nuanu-ai/agentbrowse 0.2.7 → 0.2.9
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 +36 -8
- package/dist/agentpay-stagehand-llm.d.ts.map +1 -1
- package/dist/agentpay-stagehand-llm.js +5 -1
- package/dist/commands/act.d.ts +6 -2
- package/dist/commands/act.d.ts.map +1 -1
- package/dist/commands/act.js +840 -55
- package/dist/commands/act.test-harness.d.ts +19 -0
- package/dist/commands/act.test-harness.d.ts.map +1 -0
- package/dist/commands/act.test-harness.js +245 -0
- package/dist/commands/action-acceptance.d.ts +90 -0
- package/dist/commands/action-acceptance.d.ts.map +1 -0
- package/dist/commands/action-acceptance.js +1411 -0
- package/dist/commands/action-artifacts.d.ts +33 -0
- package/dist/commands/action-artifacts.d.ts.map +1 -0
- package/dist/commands/action-artifacts.js +104 -0
- package/dist/commands/action-execution-guards.d.ts +5 -0
- package/dist/commands/action-execution-guards.d.ts.map +1 -0
- package/dist/commands/action-execution-guards.js +3 -0
- package/dist/commands/action-executor-helpers.d.ts +21 -0
- package/dist/commands/action-executor-helpers.d.ts.map +1 -0
- package/dist/commands/action-executor-helpers.js +242 -0
- package/dist/commands/action-executor.d.ts +12 -0
- package/dist/commands/action-executor.d.ts.map +1 -0
- package/dist/commands/action-executor.js +45 -0
- package/dist/commands/action-fallbacks.d.ts +6 -0
- package/dist/commands/action-fallbacks.d.ts.map +1 -0
- package/dist/commands/action-fallbacks.js +43 -0
- package/dist/commands/action-value-projection.d.ts +32 -0
- package/dist/commands/action-value-projection.d.ts.map +1 -0
- package/dist/commands/action-value-projection.js +151 -0
- package/dist/commands/browse-actions.d.ts +4 -0
- package/dist/commands/browse-actions.d.ts.map +1 -0
- package/dist/commands/browse-actions.js +4 -0
- package/dist/commands/captcha-solve.d.ts.map +1 -1
- package/dist/commands/captcha-solve.js +13 -3
- package/dist/commands/click-action-executor.d.ts +10 -0
- package/dist/commands/click-action-executor.d.ts.map +1 -0
- package/dist/commands/click-action-executor.js +68 -0
- package/dist/commands/create-intent.d.ts +6 -0
- package/dist/commands/create-intent.d.ts.map +1 -0
- package/dist/commands/create-intent.js +75 -0
- package/dist/commands/datepicker-action-executor.d.ts +12 -0
- package/dist/commands/datepicker-action-executor.d.ts.map +1 -0
- package/dist/commands/datepicker-action-executor.js +218 -0
- package/dist/commands/descriptor-validation.d.ts +27 -0
- package/dist/commands/descriptor-validation.d.ts.map +1 -0
- package/dist/commands/descriptor-validation.js +333 -0
- package/dist/commands/extract-scope-resolution.d.ts +20 -0
- package/dist/commands/extract-scope-resolution.d.ts.map +1 -0
- package/dist/commands/extract-scope-resolution.js +100 -0
- package/dist/commands/extract-stagehand-executor.d.ts +17 -0
- package/dist/commands/extract-stagehand-executor.d.ts.map +1 -0
- package/dist/commands/extract-stagehand-executor.js +18 -0
- package/dist/commands/extract.d.ts +3 -2
- package/dist/commands/extract.d.ts.map +1 -1
- package/dist/commands/extract.js +256 -39
- package/dist/commands/fill-secret.d.ts +7 -0
- package/dist/commands/fill-secret.d.ts.map +1 -0
- package/dist/commands/fill-secret.js +371 -0
- package/dist/commands/get-secrets-catalog.d.ts +6 -0
- package/dist/commands/get-secrets-catalog.d.ts.map +1 -0
- package/dist/commands/get-secrets-catalog.js +23 -0
- package/dist/commands/launch.d.ts.map +1 -1
- package/dist/commands/launch.js +41 -7
- package/dist/commands/navigate.d.ts +2 -1
- package/dist/commands/navigate.d.ts.map +1 -1
- package/dist/commands/navigate.js +49 -12
- package/dist/commands/observe-inventory.d.ts +109 -0
- package/dist/commands/observe-inventory.d.ts.map +1 -0
- package/dist/commands/observe-inventory.js +2837 -0
- package/dist/commands/observe-persistence.d.ts +14 -0
- package/dist/commands/observe-persistence.d.ts.map +1 -0
- package/dist/commands/observe-persistence.js +170 -0
- package/dist/commands/observe-projection.d.ts +85 -0
- package/dist/commands/observe-projection.d.ts.map +1 -0
- package/dist/commands/observe-projection.js +141 -0
- package/dist/commands/observe-protected.d.ts +5 -0
- package/dist/commands/observe-protected.d.ts.map +1 -0
- package/dist/commands/observe-protected.js +18 -0
- package/dist/commands/observe-semantics.d.ts +10 -0
- package/dist/commands/observe-semantics.d.ts.map +1 -0
- package/dist/commands/observe-semantics.js +338 -0
- package/dist/commands/observe-stagehand.d.ts +48 -0
- package/dist/commands/observe-stagehand.d.ts.map +1 -0
- package/dist/commands/observe-stagehand.js +105 -0
- package/dist/commands/observe-surfaces.d.ts +9 -0
- package/dist/commands/observe-surfaces.d.ts.map +1 -0
- package/dist/commands/observe-surfaces.js +195 -0
- package/dist/commands/observe.d.ts +47 -1
- package/dist/commands/observe.d.ts.map +1 -1
- package/dist/commands/observe.js +173 -20
- package/dist/commands/observe.test-harness.d.ts +67 -0
- package/dist/commands/observe.test-harness.d.ts.map +1 -0
- package/dist/commands/observe.test-harness.js +107 -0
- package/dist/commands/poll-intent.d.ts +6 -0
- package/dist/commands/poll-intent.d.ts.map +1 -0
- package/dist/commands/poll-intent.js +57 -0
- package/dist/commands/screenshot.d.ts +2 -1
- package/dist/commands/screenshot.d.ts.map +1 -1
- package/dist/commands/screenshot.js +44 -12
- package/dist/commands/select-action-executor.d.ts +10 -0
- package/dist/commands/select-action-executor.d.ts.map +1 -0
- package/dist/commands/select-action-executor.js +91 -0
- package/dist/commands/semantic-observe.d.ts +24 -0
- package/dist/commands/semantic-observe.d.ts.map +1 -0
- package/dist/commands/semantic-observe.js +344 -0
- package/dist/commands/status.d.ts.map +1 -1
- package/dist/commands/status.js +75 -2
- package/dist/commands/structured-grid-action-executor.d.ts +3 -0
- package/dist/commands/structured-grid-action-executor.d.ts.map +1 -0
- package/dist/commands/structured-grid-action-executor.js +4 -0
- package/dist/commands/target-resolution.d.ts +4 -0
- package/dist/commands/target-resolution.d.ts.map +1 -0
- package/dist/commands/target-resolution.js +33 -0
- package/dist/commands/text-input-action-executor.d.ts +5 -0
- package/dist/commands/text-input-action-executor.d.ts.map +1 -0
- package/dist/commands/text-input-action-executor.js +116 -0
- package/dist/commands/user-actionable.d.ts +4 -0
- package/dist/commands/user-actionable.d.ts.map +1 -0
- package/dist/commands/user-actionable.js +95 -0
- package/dist/control-semantics.d.ts +29 -0
- package/dist/control-semantics.d.ts.map +1 -0
- package/dist/control-semantics.js +299 -0
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +95 -32
- package/dist/output.d.ts +14 -2
- package/dist/output.d.ts.map +1 -1
- package/dist/output.js +17 -29
- package/dist/playwright-runtime.d.ts +35 -0
- package/dist/playwright-runtime.d.ts.map +1 -0
- package/dist/playwright-runtime.js +224 -0
- package/dist/runtime-resolution.d.ts +9 -0
- package/dist/runtime-resolution.d.ts.map +1 -0
- package/dist/runtime-resolution.js +19 -0
- package/dist/runtime-state.d.ts +217 -0
- package/dist/runtime-state.d.ts.map +1 -0
- package/dist/runtime-state.js +629 -0
- package/dist/secrets/backend.d.ts +32 -0
- package/dist/secrets/backend.d.ts.map +1 -0
- package/dist/secrets/backend.js +169 -0
- package/dist/secrets/catalog-applicability.d.ts +5 -0
- package/dist/secrets/catalog-applicability.d.ts.map +1 -0
- package/dist/secrets/catalog-applicability.js +59 -0
- package/dist/secrets/catalog-sync.d.ts +14 -0
- package/dist/secrets/catalog-sync.d.ts.map +1 -0
- package/dist/secrets/catalog-sync.js +35 -0
- package/dist/secrets/field-policy.d.ts +3 -0
- package/dist/secrets/field-policy.d.ts.map +1 -0
- package/dist/secrets/field-policy.js +3 -0
- package/dist/secrets/fill-ordering.d.ts +11 -0
- package/dist/secrets/fill-ordering.d.ts.map +1 -0
- package/dist/secrets/fill-ordering.js +44 -0
- package/dist/secrets/form-matcher.d.ts +60 -0
- package/dist/secrets/form-matcher.d.ts.map +1 -0
- package/dist/secrets/form-matcher.js +608 -0
- package/dist/secrets/intent-output.d.ts +11 -0
- package/dist/secrets/intent-output.d.ts.map +1 -0
- package/dist/secrets/intent-output.js +64 -0
- package/dist/secrets/mock-agentpay-backend.d.ts +13 -0
- package/dist/secrets/mock-agentpay-backend.d.ts.map +1 -0
- package/dist/secrets/mock-agentpay-backend.js +87 -0
- package/dist/secrets/mock-agentpay-cabinet.d.ts +43 -0
- package/dist/secrets/mock-agentpay-cabinet.d.ts.map +1 -0
- package/dist/secrets/mock-agentpay-cabinet.js +195 -0
- package/dist/secrets/protected-artifact-guard.d.ts +25 -0
- package/dist/secrets/protected-artifact-guard.d.ts.map +1 -0
- package/dist/secrets/protected-artifact-guard.js +26 -0
- package/dist/secrets/protected-bindings.d.ts +10 -0
- package/dist/secrets/protected-bindings.d.ts.map +1 -0
- package/dist/secrets/protected-bindings.js +17 -0
- package/dist/secrets/protected-field-values.d.ts +13 -0
- package/dist/secrets/protected-field-values.d.ts.map +1 -0
- package/dist/secrets/protected-field-values.js +100 -0
- package/dist/secrets/protected-fill.d.ts +47 -0
- package/dist/secrets/protected-fill.d.ts.map +1 -0
- package/dist/secrets/protected-fill.js +512 -0
- package/dist/secrets/request-guidance.d.ts +24 -0
- package/dist/secrets/request-guidance.d.ts.map +1 -0
- package/dist/secrets/request-guidance.js +142 -0
- package/dist/secrets/types.d.ts +91 -0
- package/dist/secrets/types.d.ts.map +1 -0
- package/dist/secrets/types.js +27 -0
- package/dist/session.d.ts +22 -0
- package/dist/session.d.ts.map +1 -1
- package/dist/session.js +74 -2
- package/dist/solver/browser-launcher.d.ts.map +1 -1
- package/dist/solver/browser-launcher.js +6 -3
- package/dist/stagehand-runtime.d.ts +4 -0
- package/dist/stagehand-runtime.d.ts.map +1 -0
- package/dist/stagehand-runtime.js +10 -0
- package/dist/stagehand.d.ts +0 -5
- package/dist/stagehand.d.ts.map +1 -1
- package/dist/stagehand.js +0 -6
- package/package.json +5 -2
|
@@ -0,0 +1,91 @@
|
|
|
1
|
+
export declare const LOGIN_FIELD_KEYS: readonly ["username", "password"];
|
|
2
|
+
export declare const IDENTITY_FIELD_KEYS: readonly ["full_name", "document_number", "date_of_birth", "nationality", "issue_date", "expiry_date", "issuing_country"];
|
|
3
|
+
export declare const PAYMENT_CARD_FIELD_KEYS: readonly ["cardholder", "pan", "exp_month", "exp_year", "cvv"];
|
|
4
|
+
export type StoredSecretKind = 'login' | 'identity' | 'payment_card';
|
|
5
|
+
export declare const STORED_SECRET_FIELD_KEYS_BY_KIND: {
|
|
6
|
+
readonly login: readonly ["username", "password"];
|
|
7
|
+
readonly identity: readonly ["full_name", "document_number", "date_of_birth", "nationality", "issue_date", "expiry_date", "issuing_country"];
|
|
8
|
+
readonly payment_card: readonly ["cardholder", "pan", "exp_month", "exp_year", "cvv"];
|
|
9
|
+
};
|
|
10
|
+
export type LoginFieldKey = (typeof LOGIN_FIELD_KEYS)[number];
|
|
11
|
+
export type IdentityFieldKey = (typeof IDENTITY_FIELD_KEYS)[number];
|
|
12
|
+
export type PaymentCardFieldKey = (typeof PAYMENT_CARD_FIELD_KEYS)[number];
|
|
13
|
+
export type StoredSecretFieldKey = LoginFieldKey | IdentityFieldKey | PaymentCardFieldKey;
|
|
14
|
+
export type StoredSecretScope = 'site' | 'global';
|
|
15
|
+
export type ProtectedFieldPolicy = 'deterministic_only' | 'llm_assisted';
|
|
16
|
+
export declare const PROTECTED_BINDING_VALUE_HINTS: readonly ["direct", "full_name.given", "full_name.family"];
|
|
17
|
+
export type ProtectedBindingValueHint = (typeof PROTECTED_BINDING_VALUE_HINTS)[number];
|
|
18
|
+
export type StoredSecretApplicabilityTarget = 'host' | 'site' | 'global';
|
|
19
|
+
export interface StoredSecretApplicability {
|
|
20
|
+
target: StoredSecretApplicabilityTarget;
|
|
21
|
+
value?: string;
|
|
22
|
+
}
|
|
23
|
+
export type StoredSecretFieldPolicies = Partial<Record<StoredSecretFieldKey, ProtectedFieldPolicy>>;
|
|
24
|
+
export interface StoredSecretMetadata {
|
|
25
|
+
storedSecretRef: string;
|
|
26
|
+
kind: StoredSecretKind;
|
|
27
|
+
scope: StoredSecretScope;
|
|
28
|
+
displayName: string;
|
|
29
|
+
fieldKeys: StoredSecretFieldKey[];
|
|
30
|
+
fieldPolicies?: StoredSecretFieldPolicies;
|
|
31
|
+
intentRequired: boolean;
|
|
32
|
+
applicability: StoredSecretApplicability;
|
|
33
|
+
preferredForMerchantKeys?: string[];
|
|
34
|
+
}
|
|
35
|
+
export interface SecretCatalogSnapshot {
|
|
36
|
+
source: 'mock' | 'agentpay_api';
|
|
37
|
+
host: string;
|
|
38
|
+
syncedAt: string;
|
|
39
|
+
storedSecrets: StoredSecretMetadata[];
|
|
40
|
+
}
|
|
41
|
+
export interface FillableFormFieldBinding {
|
|
42
|
+
fieldKey: StoredSecretFieldKey;
|
|
43
|
+
targetRef: string;
|
|
44
|
+
label?: string;
|
|
45
|
+
required?: boolean;
|
|
46
|
+
valueHint?: ProtectedBindingValueHint;
|
|
47
|
+
}
|
|
48
|
+
export interface FillableFormGuidanceHint {
|
|
49
|
+
hint: string;
|
|
50
|
+
why: string;
|
|
51
|
+
recheckWhen?: string;
|
|
52
|
+
evidence: string[];
|
|
53
|
+
}
|
|
54
|
+
export interface FillableFormStoredSecretCandidate {
|
|
55
|
+
storedSecretRef: string;
|
|
56
|
+
kind: StoredSecretKind;
|
|
57
|
+
scope: StoredSecretScope;
|
|
58
|
+
displayName: string;
|
|
59
|
+
matchConfidence: 'high' | 'medium' | 'low';
|
|
60
|
+
intentRequired: boolean;
|
|
61
|
+
fieldKeys?: StoredSecretFieldKey[];
|
|
62
|
+
fieldPolicies?: StoredSecretFieldPolicies;
|
|
63
|
+
}
|
|
64
|
+
export type FillableFormRecommendedTiming = 'late';
|
|
65
|
+
export interface PersistedFillableForm {
|
|
66
|
+
fillRef: string;
|
|
67
|
+
pageRef: string;
|
|
68
|
+
scopeRef?: string;
|
|
69
|
+
purpose: string;
|
|
70
|
+
recommendedTiming?: FillableFormRecommendedTiming;
|
|
71
|
+
guidance?: FillableFormGuidanceHint;
|
|
72
|
+
fields: FillableFormFieldBinding[];
|
|
73
|
+
storedSecretCandidates: FillableFormStoredSecretCandidate[];
|
|
74
|
+
observedAt: string;
|
|
75
|
+
}
|
|
76
|
+
export type SecretIntentStatus = 'pending' | 'checking' | 'notify' | 'confirmation' | 'approved' | 'denied' | 'timed_out' | 'completed';
|
|
77
|
+
export interface SecretIntentSnapshot {
|
|
78
|
+
intentId: string;
|
|
79
|
+
fillRef: string;
|
|
80
|
+
storedSecretRef: string;
|
|
81
|
+
status: SecretIntentStatus;
|
|
82
|
+
approvalChannel?: 'agentpay-cabinet';
|
|
83
|
+
host?: string;
|
|
84
|
+
pageRef?: string;
|
|
85
|
+
scopeRef?: string;
|
|
86
|
+
createdAt: string;
|
|
87
|
+
expiresAt?: string;
|
|
88
|
+
approvedAt?: string;
|
|
89
|
+
completedAt?: string;
|
|
90
|
+
}
|
|
91
|
+
//# sourceMappingURL=types.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"types.d.ts","sourceRoot":"","sources":["../../src/secrets/types.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,27 @@
|
|
|
1
|
+
export const LOGIN_FIELD_KEYS = ['username', 'password'];
|
|
2
|
+
export const IDENTITY_FIELD_KEYS = [
|
|
3
|
+
'full_name',
|
|
4
|
+
'document_number',
|
|
5
|
+
'date_of_birth',
|
|
6
|
+
'nationality',
|
|
7
|
+
'issue_date',
|
|
8
|
+
'expiry_date',
|
|
9
|
+
'issuing_country',
|
|
10
|
+
];
|
|
11
|
+
export const PAYMENT_CARD_FIELD_KEYS = [
|
|
12
|
+
'cardholder',
|
|
13
|
+
'pan',
|
|
14
|
+
'exp_month',
|
|
15
|
+
'exp_year',
|
|
16
|
+
'cvv',
|
|
17
|
+
];
|
|
18
|
+
export const STORED_SECRET_FIELD_KEYS_BY_KIND = {
|
|
19
|
+
login: LOGIN_FIELD_KEYS,
|
|
20
|
+
identity: IDENTITY_FIELD_KEYS,
|
|
21
|
+
payment_card: PAYMENT_CARD_FIELD_KEYS,
|
|
22
|
+
};
|
|
23
|
+
export const PROTECTED_BINDING_VALUE_HINTS = [
|
|
24
|
+
'direct',
|
|
25
|
+
'full_name.given',
|
|
26
|
+
'full_name.family',
|
|
27
|
+
];
|
package/dist/session.d.ts
CHANGED
|
@@ -2,6 +2,17 @@
|
|
|
2
2
|
* Session persistence for agentbrowse.
|
|
3
3
|
* Stores CDP URL + Chrome PID in ~/.agentpay/browse-session.json
|
|
4
4
|
*/
|
|
5
|
+
import type { BrowseRuntimeState } from './runtime-state.js';
|
|
6
|
+
import type { StoredSecretFieldKey } from './secrets/types.js';
|
|
7
|
+
export interface CachedTransientSecretEntry {
|
|
8
|
+
intentId: string;
|
|
9
|
+
fillRef: string;
|
|
10
|
+
storedSecretRef: string;
|
|
11
|
+
cachedAt: string;
|
|
12
|
+
approvedAt?: string;
|
|
13
|
+
expiresAt?: string;
|
|
14
|
+
values: Partial<Record<StoredSecretFieldKey, string>>;
|
|
15
|
+
}
|
|
5
16
|
export interface BrowseSession {
|
|
6
17
|
cdpUrl: string;
|
|
7
18
|
pid: number;
|
|
@@ -11,7 +22,18 @@ export interface BrowseSession {
|
|
|
11
22
|
capabilities?: {
|
|
12
23
|
captchaSolve?: boolean;
|
|
13
24
|
};
|
|
25
|
+
runtime?: BrowseRuntimeState;
|
|
26
|
+
transientSecretCache?: Record<string, CachedTransientSecretEntry>;
|
|
14
27
|
}
|
|
28
|
+
export declare function cleanupTransientSecretCache(session: BrowseSession, options?: {
|
|
29
|
+
now?: string;
|
|
30
|
+
}): boolean;
|
|
31
|
+
export declare function cacheTransientSecret(session: BrowseSession, entry: CachedTransientSecretEntry): CachedTransientSecretEntry;
|
|
32
|
+
export declare function getCachedTransientSecret(session: BrowseSession, intentId: string, options?: {
|
|
33
|
+
now?: string;
|
|
34
|
+
}): CachedTransientSecretEntry | null;
|
|
35
|
+
export declare function deleteCachedTransientSecret(session: BrowseSession, intentId: string): boolean;
|
|
36
|
+
export declare function serializeSession(session: BrowseSession): string;
|
|
15
37
|
export declare function saveSession(session: BrowseSession): void;
|
|
16
38
|
export declare function loadSession(): BrowseSession | null;
|
|
17
39
|
export declare function getSessionPort(session: BrowseSession | null): number;
|
package/dist/session.d.ts.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"session.d.ts","sourceRoot":"","sources":["../src/session.ts"],"names":[],"mappings":"AAAA;;;GAGG;
|
|
1
|
+
{"version":3,"file":"session.d.ts","sourceRoot":"","sources":["../src/session.ts"],"names":[],"mappings":"AAAA;;;GAGG;AAKH,OAAO,KAAK,EAAE,kBAAkB,EAAE,MAAM,oBAAoB,CAAC;AAC7D,OAAO,KAAK,EAAE,oBAAoB,EAAE,MAAM,oBAAoB,CAAC;AAK/D,MAAM,WAAW,0BAA0B;IACzC,QAAQ,EAAE,MAAM,CAAC;IACjB,OAAO,EAAE,MAAM,CAAC;IAChB,eAAe,EAAE,MAAM,CAAC;IACxB,QAAQ,EAAE,MAAM,CAAC;IACjB,UAAU,CAAC,EAAE,MAAM,CAAC;IACpB,SAAS,CAAC,EAAE,MAAM,CAAC;IACnB,MAAM,EAAE,OAAO,CAAC,MAAM,CAAC,oBAAoB,EAAE,MAAM,CAAC,CAAC,CAAC;CACvD;AAED,MAAM,WAAW,aAAa;IAC5B,MAAM,EAAE,MAAM,CAAC;IACf,GAAG,EAAE,MAAM,CAAC;IACZ,UAAU,EAAE,MAAM,CAAC;IACnB,IAAI,CAAC,EAAE,MAAM,CAAC;IACd,OAAO,CAAC,EAAE,MAAM,CAAC;IACjB,YAAY,CAAC,EAAE;QACb,YAAY,CAAC,EAAE,OAAO,CAAC;KACxB,CAAC;IACF,OAAO,CAAC,EAAE,kBAAkB,CAAC;IAC7B,oBAAoB,CAAC,EAAE,MAAM,CAAC,MAAM,EAAE,0BAA0B,CAAC,CAAC;CACnE;AAyBD,wBAAgB,2BAA2B,CACzC,OAAO,EAAE,aAAa,EACtB,OAAO,GAAE;IAAE,GAAG,CAAC,EAAE,MAAM,CAAA;CAAO,GAC7B,OAAO,CAqBT;AAED,wBAAgB,oBAAoB,CAClC,OAAO,EAAE,aAAa,EACtB,KAAK,EAAE,0BAA0B,GAChC,0BAA0B,CAQ5B;AAED,wBAAgB,wBAAwB,CACtC,OAAO,EAAE,aAAa,EACtB,QAAQ,EAAE,MAAM,EAChB,OAAO,GAAE;IAAE,GAAG,CAAC,EAAE,MAAM,CAAA;CAAO,GAC7B,0BAA0B,GAAG,IAAI,CAMnC;AAED,wBAAgB,2BAA2B,CAAC,OAAO,EAAE,aAAa,EAAE,QAAQ,EAAE,MAAM,GAAG,OAAO,CAW7F;AAED,wBAAgB,gBAAgB,CAAC,OAAO,EAAE,aAAa,GAAG,MAAM,CAW/D;AAED,wBAAgB,WAAW,CAAC,OAAO,EAAE,aAAa,GAAG,IAAI,CAGxD;AAED,wBAAgB,WAAW,IAAI,aAAa,GAAG,IAAI,CAclD;AAED,wBAAgB,cAAc,CAAC,OAAO,EAAE,aAAa,GAAG,IAAI,GAAG,MAAM,CAapE;AAED,wBAAgB,aAAa,IAAI,IAAI,CAEpC;AAED,wBAAgB,oBAAoB,CAAC,OAAO,EAAE,aAAa,GAAG,IAAI,GAAG,OAAO,CAE3E;AAED,mEAAmE;AACnE,wBAAgB,cAAc,CAAC,OAAO,EAAE,aAAa,GAAG,OAAO,CAO9D"}
|
package/dist/session.js
CHANGED
|
@@ -7,14 +7,81 @@ import { homedir } from 'node:os';
|
|
|
7
7
|
import { join } from 'node:path';
|
|
8
8
|
const SESSION_DIR = join(homedir(), '.agentpay');
|
|
9
9
|
const SESSION_PATH = join(SESSION_DIR, 'browse-session.json');
|
|
10
|
+
const BLOCKED_SESSION_KEYS = new Set([
|
|
11
|
+
'rawValue',
|
|
12
|
+
'rawValues',
|
|
13
|
+
'secretValue',
|
|
14
|
+
'secretValues',
|
|
15
|
+
'resolvedValues',
|
|
16
|
+
'protectedValues',
|
|
17
|
+
]);
|
|
10
18
|
function ensureDir() {
|
|
11
19
|
if (!existsSync(SESSION_DIR)) {
|
|
12
20
|
mkdirSync(SESSION_DIR, { recursive: true });
|
|
13
21
|
}
|
|
14
22
|
}
|
|
23
|
+
function isExpired(expiresAt, now) {
|
|
24
|
+
if (!expiresAt) {
|
|
25
|
+
return false;
|
|
26
|
+
}
|
|
27
|
+
return new Date(expiresAt).getTime() <= new Date(now).getTime();
|
|
28
|
+
}
|
|
29
|
+
export function cleanupTransientSecretCache(session, options = {}) {
|
|
30
|
+
const cache = session.transientSecretCache;
|
|
31
|
+
if (!cache) {
|
|
32
|
+
return false;
|
|
33
|
+
}
|
|
34
|
+
const now = options.now ?? new Date().toISOString();
|
|
35
|
+
let changed = false;
|
|
36
|
+
for (const [intentId, entry] of Object.entries(cache)) {
|
|
37
|
+
if (isExpired(entry.expiresAt, now)) {
|
|
38
|
+
delete cache[intentId];
|
|
39
|
+
changed = true;
|
|
40
|
+
}
|
|
41
|
+
}
|
|
42
|
+
if (Object.keys(cache).length === 0) {
|
|
43
|
+
delete session.transientSecretCache;
|
|
44
|
+
changed = true;
|
|
45
|
+
}
|
|
46
|
+
return changed;
|
|
47
|
+
}
|
|
48
|
+
export function cacheTransientSecret(session, entry) {
|
|
49
|
+
cleanupTransientSecretCache(session);
|
|
50
|
+
const cache = (session.transientSecretCache ??= {});
|
|
51
|
+
cache[entry.intentId] = {
|
|
52
|
+
...entry,
|
|
53
|
+
values: { ...entry.values },
|
|
54
|
+
};
|
|
55
|
+
return cache[entry.intentId];
|
|
56
|
+
}
|
|
57
|
+
export function getCachedTransientSecret(session, intentId, options = {}) {
|
|
58
|
+
if (cleanupTransientSecretCache(session, options)) {
|
|
59
|
+
// Keep the in-memory session sanitized for callers that save immediately after load.
|
|
60
|
+
}
|
|
61
|
+
return session.transientSecretCache?.[intentId] ?? null;
|
|
62
|
+
}
|
|
63
|
+
export function deleteCachedTransientSecret(session, intentId) {
|
|
64
|
+
const cache = session.transientSecretCache;
|
|
65
|
+
if (!cache?.[intentId]) {
|
|
66
|
+
return false;
|
|
67
|
+
}
|
|
68
|
+
delete cache[intentId];
|
|
69
|
+
if (Object.keys(cache).length === 0) {
|
|
70
|
+
delete session.transientSecretCache;
|
|
71
|
+
}
|
|
72
|
+
return true;
|
|
73
|
+
}
|
|
74
|
+
export function serializeSession(session) {
|
|
75
|
+
return JSON.stringify(session, (key, value) => {
|
|
76
|
+
if (BLOCKED_SESSION_KEYS.has(key)) {
|
|
77
|
+
return undefined;
|
|
78
|
+
}
|
|
79
|
+
return value;
|
|
80
|
+
}, 2);
|
|
81
|
+
}
|
|
15
82
|
export function saveSession(session) {
|
|
16
83
|
ensureDir();
|
|
17
|
-
writeFileSync(SESSION_PATH,
|
|
84
|
+
writeFileSync(SESSION_PATH, serializeSession(session));
|
|
18
85
|
}
|
|
19
86
|
export function loadSession() {
|
|
20
87
|
if (!existsSync(SESSION_PATH))
|
|
@@ -23,7 +90,12 @@ export function loadSession() {
|
|
|
23
90
|
const raw = JSON.parse(readFileSync(SESSION_PATH, 'utf-8'));
|
|
24
91
|
if (!raw.cdpUrl || !raw.pid)
|
|
25
92
|
return null;
|
|
26
|
-
|
|
93
|
+
const session = raw;
|
|
94
|
+
const changed = cleanupTransientSecretCache(session);
|
|
95
|
+
if (changed) {
|
|
96
|
+
saveSession(session);
|
|
97
|
+
}
|
|
98
|
+
return session;
|
|
27
99
|
}
|
|
28
100
|
catch {
|
|
29
101
|
return null;
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"browser-launcher.d.ts","sourceRoot":"","sources":["../../src/solver/browser-launcher.ts"],"names":[],"mappings":"AAMA,OAAO,KAAK,EAAE,OAAO,EAAE,IAAI,EAAE,MAAM,WAAW,CAAC;AAC/C,OAAO,KAAK,EAAsB,aAAa,EAAE,WAAW,EAAE,MAAM,YAAY,CAAC;AAWjF,MAAM,MAAM,aAAa,GAAG;IAC1B,OAAO,EAAE,OAAO,CAAC;IACjB,IAAI,EAAE,IAAI,CAAC;IACX,MAAM,EAAE,MAAM,CAAC;IACf,OAAO,EAAE,WAAW,CAAC;IACrB,KAAK,EAAE,MAAM,OAAO,CAAC,IAAI,CAAC,CAAC;IAC3B,UAAU,EAAE,MAAM,OAAO,CAAC,IAAI,CAAC,CAAC;CACjC,CAAC;
|
|
1
|
+
{"version":3,"file":"browser-launcher.d.ts","sourceRoot":"","sources":["../../src/solver/browser-launcher.ts"],"names":[],"mappings":"AAMA,OAAO,KAAK,EAAE,OAAO,EAAE,IAAI,EAAE,MAAM,WAAW,CAAC;AAC/C,OAAO,KAAK,EAAsB,aAAa,EAAE,WAAW,EAAE,MAAM,YAAY,CAAC;AAWjF,MAAM,MAAM,aAAa,GAAG;IAC1B,OAAO,EAAE,OAAO,CAAC;IACjB,IAAI,EAAE,IAAI,CAAC;IACX,MAAM,EAAE,MAAM,CAAC;IACf,OAAO,EAAE,WAAW,CAAC;IACrB,KAAK,EAAE,MAAM,OAAO,CAAC,IAAI,CAAC,CAAC;IAC3B,UAAU,EAAE,MAAM,OAAO,CAAC,IAAI,CAAC,CAAC;CACjC,CAAC;AAgBF,wBAAsB,YAAY,CAChC,OAAO,EAAE,WAAW,EACpB,IAAI,CAAC,EAAE,aAAa,GACnB,OAAO,CAAC,aAAa,CAAC,CA0ExB"}
|
|
@@ -7,6 +7,8 @@ import StealthPlugin from 'puppeteer-extra-plugin-stealth';
|
|
|
7
7
|
const enhancedPuppeteer = puppeteerExtra;
|
|
8
8
|
enhancedPuppeteer.use(StealthPlugin());
|
|
9
9
|
const DEFAULT_CDP_PORT = 9222;
|
|
10
|
+
const CDP_DISCOVERY_ATTEMPTS = 20;
|
|
11
|
+
const CDP_DISCOVERY_INTERVAL_MS = 500;
|
|
10
12
|
const CHROME_PATHS = [
|
|
11
13
|
'/Applications/Google Chrome.app/Contents/MacOS/Google Chrome',
|
|
12
14
|
'/Applications/Google Chrome Canary.app/Contents/MacOS/Google Chrome Canary',
|
|
@@ -84,9 +86,9 @@ export async function launchSolver(profile, opts) {
|
|
|
84
86
|
}
|
|
85
87
|
}
|
|
86
88
|
async function discoverCdpUrl(port) {
|
|
87
|
-
for (let i = 0; i <
|
|
89
|
+
for (let i = 0; i < CDP_DISCOVERY_ATTEMPTS; i++) {
|
|
88
90
|
try {
|
|
89
|
-
const res = await fetch(`http://
|
|
91
|
+
const res = await fetch(`http://127.0.0.1:${port}/json/version`);
|
|
90
92
|
if (!res.ok)
|
|
91
93
|
throw new Error(`CDP endpoint returned ${res.status}`);
|
|
92
94
|
const json = (await res.json());
|
|
@@ -97,7 +99,7 @@ async function discoverCdpUrl(port) {
|
|
|
97
99
|
catch {
|
|
98
100
|
// Retry while Chrome is initializing.
|
|
99
101
|
}
|
|
100
|
-
await new Promise((resolve) => setTimeout(resolve,
|
|
102
|
+
await new Promise((resolve) => setTimeout(resolve, CDP_DISCOVERY_INTERVAL_MS));
|
|
101
103
|
}
|
|
102
104
|
return null;
|
|
103
105
|
}
|
|
@@ -161,6 +163,7 @@ function spawnChromeProcess(executablePath, profile, fp, cdpPort, windowSize, he
|
|
|
161
163
|
const height = windowSize?.height ?? fp.viewport.height;
|
|
162
164
|
const args = [
|
|
163
165
|
`--remote-debugging-port=${cdpPort}`,
|
|
166
|
+
'--remote-debugging-address=127.0.0.1',
|
|
164
167
|
`--user-data-dir=${profile.userDataDir}`,
|
|
165
168
|
`--window-size=${width},${height}`,
|
|
166
169
|
'--disable-blink-features=AutomationControlled',
|
|
@@ -0,0 +1,4 @@
|
|
|
1
|
+
import type { Stagehand } from '@browserbasehq/stagehand';
|
|
2
|
+
import type { BrowseSession } from './session.js';
|
|
3
|
+
export declare function withStagehand<T>(session: BrowseSession, run: (stagehand: Stagehand) => Promise<T>): Promise<T>;
|
|
4
|
+
//# sourceMappingURL=stagehand-runtime.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"stagehand-runtime.d.ts","sourceRoot":"","sources":["../src/stagehand-runtime.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,SAAS,EAAE,MAAM,0BAA0B,CAAC;AAC1D,OAAO,KAAK,EAAE,aAAa,EAAE,MAAM,cAAc,CAAC;AAGlD,wBAAsB,aAAa,CAAC,CAAC,EACnC,OAAO,EAAE,aAAa,EACtB,GAAG,EAAE,CAAC,SAAS,EAAE,SAAS,KAAK,OAAO,CAAC,CAAC,CAAC,GACxC,OAAO,CAAC,CAAC,CAAC,CAOZ"}
|
|
@@ -0,0 +1,10 @@
|
|
|
1
|
+
import { connectStagehand } from './stagehand.js';
|
|
2
|
+
export async function withStagehand(session, run) {
|
|
3
|
+
const stagehand = await connectStagehand(session.cdpUrl);
|
|
4
|
+
try {
|
|
5
|
+
return await run(stagehand);
|
|
6
|
+
}
|
|
7
|
+
finally {
|
|
8
|
+
await stagehand.close().catch(() => undefined);
|
|
9
|
+
}
|
|
10
|
+
}
|
package/dist/stagehand.d.ts
CHANGED
|
@@ -12,9 +12,4 @@ export interface StagehandSession {
|
|
|
12
12
|
export declare function connectStagehand(cdpUrl: string): Promise<Stagehand>;
|
|
13
13
|
/** Find the PID of the Chrome process listening on CDP_PORT. */
|
|
14
14
|
export declare function findChromePid(port?: number): number | null;
|
|
15
|
-
/** Get current page URL and title from Stagehand. */
|
|
16
|
-
export declare function getPageInfo(stagehand: Stagehand): Promise<{
|
|
17
|
-
url: string;
|
|
18
|
-
title: string;
|
|
19
|
-
}>;
|
|
20
15
|
//# sourceMappingURL=stagehand.d.ts.map
|
package/dist/stagehand.d.ts.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"stagehand.d.ts","sourceRoot":"","sources":["../src/stagehand.ts"],"names":[],"mappings":"AAAA;;;;;GAKG;AAGH,OAAO,EAAE,SAAS,EAAE,MAAM,0BAA0B,CAAC;AAMrD,MAAM,WAAW,gBAAgB;IAC/B,SAAS,EAAE,SAAS,CAAC;CACtB;AAED,kDAAkD;AAClD,wBAAsB,gBAAgB,CAAC,MAAM,EAAE,MAAM,GAAG,OAAO,CAAC,SAAS,CAAC,CAezE;AAED,gEAAgE;AAChE,wBAAgB,aAAa,CAAC,IAAI,SAAmB,GAAG,MAAM,GAAG,IAAI,CAQpE
|
|
1
|
+
{"version":3,"file":"stagehand.d.ts","sourceRoot":"","sources":["../src/stagehand.ts"],"names":[],"mappings":"AAAA;;;;;GAKG;AAGH,OAAO,EAAE,SAAS,EAAE,MAAM,0BAA0B,CAAC;AAMrD,MAAM,WAAW,gBAAgB;IAC/B,SAAS,EAAE,SAAS,CAAC;CACtB;AAED,kDAAkD;AAClD,wBAAsB,gBAAgB,CAAC,MAAM,EAAE,MAAM,GAAG,OAAO,CAAC,SAAS,CAAC,CAezE;AAED,gEAAgE;AAChE,wBAAgB,aAAa,CAAC,IAAI,SAAmB,GAAG,MAAM,GAAG,IAAI,CAQpE"}
|
package/dist/stagehand.js
CHANGED
|
@@ -36,9 +36,3 @@ export function findChromePid(port = DEFAULT_CDP_PORT) {
|
|
|
36
36
|
return null;
|
|
37
37
|
}
|
|
38
38
|
}
|
|
39
|
-
/** Get current page URL and title from Stagehand. */
|
|
40
|
-
export async function getPageInfo(stagehand) {
|
|
41
|
-
const page = stagehand.context.pages()[0];
|
|
42
|
-
const [url, title] = await Promise.all([page.url(), page.title()]);
|
|
43
|
-
return { url, title };
|
|
44
|
-
}
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@nuanu-ai/agentbrowse",
|
|
3
|
-
"version": "0.2.
|
|
3
|
+
"version": "0.2.9",
|
|
4
4
|
"type": "module",
|
|
5
5
|
"description": "Standalone browser automation CLI for AI agents: launch, observe, act, extract, and solve captcha",
|
|
6
6
|
"keywords": [
|
|
@@ -43,7 +43,9 @@
|
|
|
43
43
|
"scripts": {
|
|
44
44
|
"build": "node -e \"require('node:fs').rmSync('dist',{ recursive: true, force: true })\" && tsc -p tsconfig.build.json",
|
|
45
45
|
"agentbrowse": "tsx src/index.ts",
|
|
46
|
-
"test": "
|
|
46
|
+
"test": "pnpm run test:unit && pnpm run test:e2e",
|
|
47
|
+
"test:unit": "vitest run --exclude \"src/__tests__/*.e2e.test.ts\"",
|
|
48
|
+
"test:e2e": "vitest run --no-file-parallelism --maxWorkers=1 src/__tests__/observe-stagehand.e2e.test.ts src/__tests__/extract.e2e.test.ts src/__tests__/protected-fill.e2e.test.ts src/__tests__/runtime.e2e.test.ts",
|
|
47
49
|
"check-types": "tsc --noEmit",
|
|
48
50
|
"lint": "biome check .",
|
|
49
51
|
"prepack": "pnpm run build"
|
|
@@ -51,6 +53,7 @@
|
|
|
51
53
|
"dependencies": {
|
|
52
54
|
"@browserbasehq/stagehand": "^3.0.0",
|
|
53
55
|
"dotenv": "^16.4.0",
|
|
56
|
+
"playwright-core": "^1.58.2",
|
|
54
57
|
"puppeteer": "^23.11.1",
|
|
55
58
|
"puppeteer-extra": "^3.3.6",
|
|
56
59
|
"puppeteer-extra-plugin-stealth": "^2.11.2",
|