@nuanu-ai/agentbrowse 0.2.7 → 0.2.8

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 (191) hide show
  1. package/README.md +36 -8
  2. package/dist/agentpay-stagehand-llm.d.ts.map +1 -1
  3. package/dist/agentpay-stagehand-llm.js +5 -1
  4. package/dist/commands/act.d.ts +6 -2
  5. package/dist/commands/act.d.ts.map +1 -1
  6. package/dist/commands/act.js +840 -55
  7. package/dist/commands/act.test-harness.d.ts +19 -0
  8. package/dist/commands/act.test-harness.d.ts.map +1 -0
  9. package/dist/commands/act.test-harness.js +245 -0
  10. package/dist/commands/action-acceptance.d.ts +90 -0
  11. package/dist/commands/action-acceptance.d.ts.map +1 -0
  12. package/dist/commands/action-acceptance.js +1411 -0
  13. package/dist/commands/action-artifacts.d.ts +33 -0
  14. package/dist/commands/action-artifacts.d.ts.map +1 -0
  15. package/dist/commands/action-artifacts.js +104 -0
  16. package/dist/commands/action-execution-guards.d.ts +5 -0
  17. package/dist/commands/action-execution-guards.d.ts.map +1 -0
  18. package/dist/commands/action-execution-guards.js +3 -0
  19. package/dist/commands/action-executor-helpers.d.ts +21 -0
  20. package/dist/commands/action-executor-helpers.d.ts.map +1 -0
  21. package/dist/commands/action-executor-helpers.js +242 -0
  22. package/dist/commands/action-executor.d.ts +12 -0
  23. package/dist/commands/action-executor.d.ts.map +1 -0
  24. package/dist/commands/action-executor.js +45 -0
  25. package/dist/commands/action-fallbacks.d.ts +6 -0
  26. package/dist/commands/action-fallbacks.d.ts.map +1 -0
  27. package/dist/commands/action-fallbacks.js +43 -0
  28. package/dist/commands/action-value-projection.d.ts +32 -0
  29. package/dist/commands/action-value-projection.d.ts.map +1 -0
  30. package/dist/commands/action-value-projection.js +151 -0
  31. package/dist/commands/browse-actions.d.ts +4 -0
  32. package/dist/commands/browse-actions.d.ts.map +1 -0
  33. package/dist/commands/browse-actions.js +4 -0
  34. package/dist/commands/captcha-solve.d.ts.map +1 -1
  35. package/dist/commands/captcha-solve.js +13 -3
  36. package/dist/commands/click-action-executor.d.ts +10 -0
  37. package/dist/commands/click-action-executor.d.ts.map +1 -0
  38. package/dist/commands/click-action-executor.js +68 -0
  39. package/dist/commands/create-intent.d.ts +6 -0
  40. package/dist/commands/create-intent.d.ts.map +1 -0
  41. package/dist/commands/create-intent.js +75 -0
  42. package/dist/commands/datepicker-action-executor.d.ts +12 -0
  43. package/dist/commands/datepicker-action-executor.d.ts.map +1 -0
  44. package/dist/commands/datepicker-action-executor.js +218 -0
  45. package/dist/commands/descriptor-validation.d.ts +27 -0
  46. package/dist/commands/descriptor-validation.d.ts.map +1 -0
  47. package/dist/commands/descriptor-validation.js +333 -0
  48. package/dist/commands/extract-scope-resolution.d.ts +20 -0
  49. package/dist/commands/extract-scope-resolution.d.ts.map +1 -0
  50. package/dist/commands/extract-scope-resolution.js +100 -0
  51. package/dist/commands/extract-stagehand-executor.d.ts +17 -0
  52. package/dist/commands/extract-stagehand-executor.d.ts.map +1 -0
  53. package/dist/commands/extract-stagehand-executor.js +18 -0
  54. package/dist/commands/extract.d.ts +3 -2
  55. package/dist/commands/extract.d.ts.map +1 -1
  56. package/dist/commands/extract.js +256 -39
  57. package/dist/commands/fill-secret.d.ts +7 -0
  58. package/dist/commands/fill-secret.d.ts.map +1 -0
  59. package/dist/commands/fill-secret.js +371 -0
  60. package/dist/commands/get-secrets-catalog.d.ts +6 -0
  61. package/dist/commands/get-secrets-catalog.d.ts.map +1 -0
  62. package/dist/commands/get-secrets-catalog.js +23 -0
  63. package/dist/commands/launch.d.ts.map +1 -1
  64. package/dist/commands/launch.js +41 -7
  65. package/dist/commands/navigate.d.ts +2 -1
  66. package/dist/commands/navigate.d.ts.map +1 -1
  67. package/dist/commands/navigate.js +49 -12
  68. package/dist/commands/observe-inventory.d.ts +109 -0
  69. package/dist/commands/observe-inventory.d.ts.map +1 -0
  70. package/dist/commands/observe-inventory.js +2837 -0
  71. package/dist/commands/observe-persistence.d.ts +14 -0
  72. package/dist/commands/observe-persistence.d.ts.map +1 -0
  73. package/dist/commands/observe-persistence.js +170 -0
  74. package/dist/commands/observe-projection.d.ts +84 -0
  75. package/dist/commands/observe-projection.d.ts.map +1 -0
  76. package/dist/commands/observe-projection.js +140 -0
  77. package/dist/commands/observe-protected.d.ts +5 -0
  78. package/dist/commands/observe-protected.d.ts.map +1 -0
  79. package/dist/commands/observe-protected.js +18 -0
  80. package/dist/commands/observe-semantics.d.ts +10 -0
  81. package/dist/commands/observe-semantics.d.ts.map +1 -0
  82. package/dist/commands/observe-semantics.js +338 -0
  83. package/dist/commands/observe-stagehand.d.ts +48 -0
  84. package/dist/commands/observe-stagehand.d.ts.map +1 -0
  85. package/dist/commands/observe-stagehand.js +105 -0
  86. package/dist/commands/observe-surfaces.d.ts +9 -0
  87. package/dist/commands/observe-surfaces.d.ts.map +1 -0
  88. package/dist/commands/observe-surfaces.js +195 -0
  89. package/dist/commands/observe.d.ts +47 -1
  90. package/dist/commands/observe.d.ts.map +1 -1
  91. package/dist/commands/observe.js +173 -20
  92. package/dist/commands/observe.test-harness.d.ts +67 -0
  93. package/dist/commands/observe.test-harness.d.ts.map +1 -0
  94. package/dist/commands/observe.test-harness.js +107 -0
  95. package/dist/commands/poll-intent.d.ts +6 -0
  96. package/dist/commands/poll-intent.d.ts.map +1 -0
  97. package/dist/commands/poll-intent.js +57 -0
  98. package/dist/commands/screenshot.d.ts +2 -1
  99. package/dist/commands/screenshot.d.ts.map +1 -1
  100. package/dist/commands/screenshot.js +44 -12
  101. package/dist/commands/select-action-executor.d.ts +10 -0
  102. package/dist/commands/select-action-executor.d.ts.map +1 -0
  103. package/dist/commands/select-action-executor.js +91 -0
  104. package/dist/commands/semantic-observe.d.ts +24 -0
  105. package/dist/commands/semantic-observe.d.ts.map +1 -0
  106. package/dist/commands/semantic-observe.js +344 -0
  107. package/dist/commands/status.d.ts.map +1 -1
  108. package/dist/commands/status.js +75 -2
  109. package/dist/commands/structured-grid-action-executor.d.ts +3 -0
  110. package/dist/commands/structured-grid-action-executor.d.ts.map +1 -0
  111. package/dist/commands/structured-grid-action-executor.js +4 -0
  112. package/dist/commands/target-resolution.d.ts +4 -0
  113. package/dist/commands/target-resolution.d.ts.map +1 -0
  114. package/dist/commands/target-resolution.js +33 -0
  115. package/dist/commands/text-input-action-executor.d.ts +5 -0
  116. package/dist/commands/text-input-action-executor.d.ts.map +1 -0
  117. package/dist/commands/text-input-action-executor.js +116 -0
  118. package/dist/commands/user-actionable.d.ts +4 -0
  119. package/dist/commands/user-actionable.d.ts.map +1 -0
  120. package/dist/commands/user-actionable.js +95 -0
  121. package/dist/control-semantics.d.ts +29 -0
  122. package/dist/control-semantics.d.ts.map +1 -0
  123. package/dist/control-semantics.js +299 -0
  124. package/dist/index.d.ts.map +1 -1
  125. package/dist/index.js +95 -32
  126. package/dist/output.d.ts +14 -2
  127. package/dist/output.d.ts.map +1 -1
  128. package/dist/output.js +17 -29
  129. package/dist/playwright-runtime.d.ts +35 -0
  130. package/dist/playwright-runtime.d.ts.map +1 -0
  131. package/dist/playwright-runtime.js +224 -0
  132. package/dist/runtime-resolution.d.ts +9 -0
  133. package/dist/runtime-resolution.d.ts.map +1 -0
  134. package/dist/runtime-resolution.js +19 -0
  135. package/dist/runtime-state.d.ts +217 -0
  136. package/dist/runtime-state.d.ts.map +1 -0
  137. package/dist/runtime-state.js +629 -0
  138. package/dist/secrets/backend.d.ts +32 -0
  139. package/dist/secrets/backend.d.ts.map +1 -0
  140. package/dist/secrets/backend.js +169 -0
  141. package/dist/secrets/catalog-applicability.d.ts +5 -0
  142. package/dist/secrets/catalog-applicability.d.ts.map +1 -0
  143. package/dist/secrets/catalog-applicability.js +59 -0
  144. package/dist/secrets/catalog-sync.d.ts +14 -0
  145. package/dist/secrets/catalog-sync.d.ts.map +1 -0
  146. package/dist/secrets/catalog-sync.js +35 -0
  147. package/dist/secrets/field-policy.d.ts +3 -0
  148. package/dist/secrets/field-policy.d.ts.map +1 -0
  149. package/dist/secrets/field-policy.js +3 -0
  150. package/dist/secrets/fill-ordering.d.ts +11 -0
  151. package/dist/secrets/fill-ordering.d.ts.map +1 -0
  152. package/dist/secrets/fill-ordering.js +44 -0
  153. package/dist/secrets/form-matcher.d.ts +60 -0
  154. package/dist/secrets/form-matcher.d.ts.map +1 -0
  155. package/dist/secrets/form-matcher.js +596 -0
  156. package/dist/secrets/intent-output.d.ts +11 -0
  157. package/dist/secrets/intent-output.d.ts.map +1 -0
  158. package/dist/secrets/intent-output.js +64 -0
  159. package/dist/secrets/mock-agentpay-backend.d.ts +13 -0
  160. package/dist/secrets/mock-agentpay-backend.d.ts.map +1 -0
  161. package/dist/secrets/mock-agentpay-backend.js +87 -0
  162. package/dist/secrets/mock-agentpay-cabinet.d.ts +43 -0
  163. package/dist/secrets/mock-agentpay-cabinet.d.ts.map +1 -0
  164. package/dist/secrets/mock-agentpay-cabinet.js +195 -0
  165. package/dist/secrets/protected-artifact-guard.d.ts +25 -0
  166. package/dist/secrets/protected-artifact-guard.d.ts.map +1 -0
  167. package/dist/secrets/protected-artifact-guard.js +26 -0
  168. package/dist/secrets/protected-bindings.d.ts +10 -0
  169. package/dist/secrets/protected-bindings.d.ts.map +1 -0
  170. package/dist/secrets/protected-bindings.js +17 -0
  171. package/dist/secrets/protected-field-values.d.ts +13 -0
  172. package/dist/secrets/protected-field-values.d.ts.map +1 -0
  173. package/dist/secrets/protected-field-values.js +100 -0
  174. package/dist/secrets/protected-fill.d.ts +47 -0
  175. package/dist/secrets/protected-fill.d.ts.map +1 -0
  176. package/dist/secrets/protected-fill.js +512 -0
  177. package/dist/secrets/types.d.ts +84 -0
  178. package/dist/secrets/types.d.ts.map +1 -0
  179. package/dist/secrets/types.js +27 -0
  180. package/dist/session.d.ts +22 -0
  181. package/dist/session.d.ts.map +1 -1
  182. package/dist/session.js +74 -2
  183. package/dist/solver/browser-launcher.d.ts.map +1 -1
  184. package/dist/solver/browser-launcher.js +6 -3
  185. package/dist/stagehand-runtime.d.ts +4 -0
  186. package/dist/stagehand-runtime.d.ts.map +1 -0
  187. package/dist/stagehand-runtime.js +10 -0
  188. package/dist/stagehand.d.ts +0 -5
  189. package/dist/stagehand.d.ts.map +1 -1
  190. package/dist/stagehand.js +0 -6
  191. package/package.json +5 -2
@@ -1,59 +1,276 @@
1
1
  /**
2
- * browse extract "<instruction>" [--schema '<json>'] — Extract structured data.
2
+ * browse extract '<schema-json>' [scopeRef] — Extract structured data from the page or a stored scope.
3
3
  */
4
4
  import { z } from 'zod';
5
- import { connectStagehand, getPageInfo } from '../stagehand.js';
6
- import { outputJSON, outputError } from '../output.js';
7
- /**
8
- * Build a Zod schema from a simple JSON type descriptor.
9
- * Supports: "string", "number", "boolean", and nested objects.
10
- *
11
- * Example: {"price": "number", "name": "string"} z.object({price: z.number(), name: z.string()})
12
- */
5
+ import { saveSession } from '../session.js';
6
+ import { getSurface, getTarget, markSurfaceLifecycle, markTargetLifecycle, setCurrentPage, } from '../runtime-state.js';
7
+ import { outputContractFailure, outputJSON } from '../output.js';
8
+ import { connectPlaywright, disconnectPlaywright, resolvePageByRef as resolvePlaywrightPageByRef, syncSessionPage, } from '../playwright-runtime.js';
9
+ import { normalizePageSignature } from './descriptor-validation.js';
10
+ import { resolveScopedExtractContext } from './extract-scope-resolution.js';
11
+ import { executeStagehandExtract } from './extract-stagehand-executor.js';
12
+ function buildSchemaValue(descriptor) {
13
+ if (descriptor === 'string')
14
+ return z.string();
15
+ if (descriptor === 'number')
16
+ return z.number();
17
+ if (descriptor === 'boolean')
18
+ return z.boolean();
19
+ if (Array.isArray(descriptor)) {
20
+ const itemDescriptor = descriptor[0];
21
+ return z.array(itemDescriptor === undefined ? z.unknown() : buildSchemaValue(itemDescriptor));
22
+ }
23
+ if (typeof descriptor === 'object' && descriptor !== null) {
24
+ const shape = {};
25
+ for (const [key, value] of Object.entries(descriptor)) {
26
+ shape[key] = buildSchemaValue(value);
27
+ }
28
+ return z.object(shape);
29
+ }
30
+ return z.unknown();
31
+ }
13
32
  function buildSchema(descriptor) {
14
- const shape = {};
33
+ return buildSchemaValue(descriptor);
34
+ }
35
+ function describeSchema(descriptor, prefix) {
36
+ const lines = [];
15
37
  for (const [key, value] of Object.entries(descriptor)) {
16
- if (value === 'string')
17
- shape[key] = z.string();
18
- else if (value === 'number')
19
- shape[key] = z.number();
20
- else if (value === 'boolean')
21
- shape[key] = z.boolean();
22
- else if (typeof value === 'object' && value !== null) {
23
- shape[key] = buildSchema(value);
38
+ const fieldPath = prefix ? `${prefix}.${key}` : key;
39
+ if (value === 'string' || value === 'number' || value === 'boolean') {
40
+ lines.push(`${fieldPath}: ${value}`);
41
+ continue;
24
42
  }
25
- else {
26
- shape[key] = z.unknown();
43
+ if (Array.isArray(value)) {
44
+ const itemDescriptor = value[0];
45
+ if (itemDescriptor === 'string' || itemDescriptor === 'number' || itemDescriptor === 'boolean') {
46
+ lines.push(`${fieldPath}[]: ${itemDescriptor}`);
47
+ }
48
+ else if (typeof itemDescriptor === 'object' && itemDescriptor !== null && !Array.isArray(itemDescriptor)) {
49
+ lines.push(...describeSchema(itemDescriptor, `${fieldPath}[]`));
50
+ }
51
+ else {
52
+ lines.push(`${fieldPath}[]: unknown`);
53
+ }
54
+ continue;
27
55
  }
56
+ if (typeof value === 'object' && value !== null) {
57
+ lines.push(...describeSchema(value, fieldPath));
58
+ continue;
59
+ }
60
+ lines.push(`${fieldPath}: unknown`);
28
61
  }
29
- return z.object(shape);
62
+ return lines;
63
+ }
64
+ function buildInstruction(schemaDescriptor, scopeRef) {
65
+ const fields = describeSchema(schemaDescriptor);
66
+ const scopeNote = scopeRef
67
+ ? 'Only inspect the provided scoped container, not the full page.'
68
+ : 'Inspect the current page.';
69
+ return [
70
+ 'Extract structured data that is explicitly visible in the current DOM state.',
71
+ scopeNote,
72
+ 'Return only the fields defined by the schema and do not infer missing values.',
73
+ `Fields: ${fields.join('; ') || 'none'}.`,
74
+ ].join(' ');
30
75
  }
31
- export async function extract(cdpUrl, instruction, schemaJson) {
32
- let stagehand;
76
+ function canUseTargetAsExtractScope(target) {
77
+ if (target.capability === 'informational') {
78
+ return false;
79
+ }
80
+ if (target.capability === 'scope') {
81
+ return true;
82
+ }
83
+ const kind = (target.kind ?? '').toLowerCase();
84
+ const role = (target.semantics?.role ?? '').toLowerCase();
85
+ const scopeLikeKinds = new Set([
86
+ 'card',
87
+ 'article',
88
+ 'section',
89
+ 'row',
90
+ 'grid',
91
+ 'gridcell',
92
+ 'listitem',
93
+ 'dialog',
94
+ 'tabpanel',
95
+ 'region',
96
+ 'form',
97
+ 'group',
98
+ ]);
99
+ const leafInteractiveKinds = new Set(['input', 'textarea', 'select', 'option', 'button', 'link', 'combobox']);
100
+ const leafInteractiveRoles = new Set(['textbox', 'combobox', 'option', 'menuitem', 'button', 'link']);
101
+ const iframeFieldLike = Boolean(target.framePath?.length) &&
102
+ (target.allowedActions.includes('fill') ||
103
+ target.allowedActions.includes('type') ||
104
+ target.allowedActions.includes('select') ||
105
+ ['input', 'textarea', 'select', 'combobox'].includes(kind) ||
106
+ ['textbox', 'combobox'].includes(role));
107
+ if (target.allowedActions.length === 0) {
108
+ return true;
109
+ }
110
+ if (iframeFieldLike) {
111
+ return true;
112
+ }
113
+ if (target.allowedActions.includes('fill') ||
114
+ target.allowedActions.includes('type') ||
115
+ target.allowedActions.includes('select')) {
116
+ return false;
117
+ }
118
+ if (leafInteractiveKinds.has(kind) || leafInteractiveRoles.has(role)) {
119
+ return false;
120
+ }
121
+ return Boolean(target.surfaceRef) || scopeLikeKinds.has(kind) || scopeLikeKinds.has(role);
122
+ }
123
+ export async function extract(session, schemaJson, scopeRef) {
124
+ let schemaDescriptor;
33
125
  try {
34
- stagehand = await connectStagehand(cdpUrl);
126
+ schemaDescriptor = JSON.parse(schemaJson);
127
+ }
128
+ catch {
129
+ return outputContractFailure({
130
+ error: 'invalid_extract_schema',
131
+ outcomeType: 'blocked',
132
+ message: 'Extraction could not start because the schema JSON is invalid.',
133
+ reason: 'The provided schema argument is not valid JSON.',
134
+ });
135
+ }
136
+ const schema = buildSchema(schemaDescriptor);
137
+ const instruction = buildInstruction(schemaDescriptor, scopeRef);
138
+ const targetScope = scopeRef ? getTarget(session, scopeRef) : null;
139
+ const surfaceScope = !targetScope && scopeRef ? getSurface(session, scopeRef) : null;
140
+ const scopeTarget = targetScope ?? surfaceScope;
141
+ const pageRef = scopeTarget?.pageRef ?? session.runtime?.currentPageRef ?? 'p0';
142
+ if (scopeRef && !scopeTarget) {
143
+ return outputContractFailure({
144
+ error: 'unknown_scope_ref',
145
+ outcomeType: 'blocked',
146
+ message: 'Extraction could not start because the requested scopeRef is unknown.',
147
+ reason: `No live scope target matches scopeRef ${scopeRef}.`,
148
+ scopeRef,
149
+ });
150
+ }
151
+ if (scopeTarget && scopeTarget.lifecycle !== 'live') {
152
+ return outputContractFailure({
153
+ error: 'stale_extract_scope',
154
+ outcomeType: 'binding_stale',
155
+ message: 'Extraction could not start because the requested scope is no longer live.',
156
+ reason: `Scope ${scopeRef} is ${scopeTarget.lifecycle}${scopeTarget.lifecycleReason ? ` because ${scopeTarget.lifecycleReason}` : ''}.`,
157
+ scopeRef,
158
+ });
159
+ }
160
+ if (targetScope && !canUseTargetAsExtractScope(targetScope)) {
161
+ return outputContractFailure({
162
+ error: 'invalid_extract_scope',
163
+ outcomeType: 'unsupported',
164
+ message: 'Extraction cannot use the requested target as a scope.',
165
+ reason: `Target ${scopeRef} is a leaf control, not an extractable scope container.`,
166
+ scopeRef,
167
+ });
168
+ }
169
+ let browser = null;
170
+ let failureMessage = null;
171
+ let cleanupScopedExtract = null;
172
+ let staleScope = false;
173
+ let staleReason = null;
174
+ try {
175
+ browser = await connectPlaywright(session.cdpUrl);
35
176
  }
36
177
  catch (err) {
37
- outputError(`Failed to connect to browser: ${err instanceof Error ? err.message : String(err)}`);
178
+ return outputContractFailure({
179
+ error: 'browser_connection_failed',
180
+ outcomeType: 'blocked',
181
+ message: 'Extraction could not start because AgentBrowse failed to connect to the browser.',
182
+ reason: err instanceof Error ? err.message : String(err),
183
+ scopeRef,
184
+ pageRef,
185
+ });
38
186
  }
39
187
  try {
40
- if (schemaJson) {
41
- const descriptor = JSON.parse(schemaJson);
42
- const schema = buildSchema(descriptor);
43
- const data = await stagehand.extract(instruction, schema);
44
- const { url, title } = await getPageInfo(stagehand);
45
- await stagehand.close();
46
- outputJSON({ success: true, data, url, title });
188
+ const sourcePage = await resolvePlaywrightPageByRef(browser, session, pageRef);
189
+ let page = sourcePage;
190
+ let scopedResolution = null;
191
+ const { url, title } = await syncSessionPage(session, pageRef, sourcePage);
192
+ if (scopeTarget?.pageSignature && normalizePageSignature(url) !== scopeTarget.pageSignature) {
193
+ staleScope = true;
194
+ staleReason = 'page-signature-mismatch';
195
+ throw new Error('stale_scope_target_page_signature_changed');
47
196
  }
48
- else {
49
- const result = await stagehand.extract(instruction);
50
- const { url, title } = await getPageInfo(stagehand);
51
- await stagehand.close();
52
- outputJSON({ success: true, extraction: result.extraction, url, title });
197
+ let effectiveSelector;
198
+ if (scopeTarget) {
199
+ try {
200
+ scopedResolution = await resolveScopedExtractContext({
201
+ page: sourcePage,
202
+ scopeTarget,
203
+ validateDomSignature: Boolean(targetScope),
204
+ });
205
+ cleanupScopedExtract = scopedResolution.cleanup;
206
+ page = scopedResolution.page;
207
+ effectiveSelector = scopedResolution.selector;
208
+ }
209
+ catch (error) {
210
+ if (error instanceof Error &&
211
+ error.message === 'stale_scope_target_dom_signature_changed') {
212
+ staleScope = true;
213
+ staleReason = 'dom-signature-mismatch';
214
+ }
215
+ throw error;
216
+ }
53
217
  }
218
+ setCurrentPage(session, pageRef);
219
+ const execution = await executeStagehandExtract({
220
+ session,
221
+ instruction,
222
+ schema,
223
+ page,
224
+ selector: effectiveSelector,
225
+ degradationReason: scopedResolution?.degraded
226
+ ? scopedResolution.degradationReason
227
+ : undefined,
228
+ });
229
+ saveSession(session);
230
+ outputJSON({
231
+ success: true,
232
+ ...execution,
233
+ pageRef,
234
+ scopeRef,
235
+ metrics: session.runtime?.metrics,
236
+ url,
237
+ title,
238
+ });
54
239
  }
55
240
  catch (err) {
56
- await stagehand.close();
57
- outputError(`Extract failed: ${err instanceof Error ? err.message : String(err)}`);
241
+ if (staleScope && scopeRef) {
242
+ if (targetScope) {
243
+ markTargetLifecycle(session, scopeRef, 'stale', staleReason ?? 'unknown');
244
+ }
245
+ else if (surfaceScope) {
246
+ markSurfaceLifecycle(session, scopeRef, 'stale', staleReason ?? 'unknown');
247
+ }
248
+ saveSession(session);
249
+ }
250
+ failureMessage = `Extract failed: ${err instanceof Error ? err.message : String(err)}`;
251
+ }
252
+ finally {
253
+ if (cleanupScopedExtract) {
254
+ await cleanupScopedExtract().catch(() => undefined);
255
+ }
256
+ if (browser) {
257
+ disconnectPlaywright(browser);
258
+ }
259
+ }
260
+ if (failureMessage) {
261
+ outputContractFailure({
262
+ error: staleScope ? 'stale_extract_scope' : 'extract_failed',
263
+ outcomeType: staleScope ? 'binding_stale' : 'blocked',
264
+ message: staleScope
265
+ ? 'Extraction failed because the requested scope became stale.'
266
+ : 'Extraction failed.',
267
+ reason: staleScope && scopeRef
268
+ ? `${failureMessage} (${scopeRef} marked stale: ${staleReason ?? 'stale'})`
269
+ : failureMessage.replace(/^Extract failed:\s*/, ''),
270
+ scopeRef,
271
+ pageRef,
272
+ staleScope,
273
+ staleReason: staleReason ?? undefined,
274
+ });
58
275
  }
59
276
  }
@@ -0,0 +1,7 @@
1
+ /**
2
+ * browse fill-secret <fillRef> <intentId> — Fill protected fields from a cached one-time secret payload
3
+ * using the persisted plan and deterministic browser execution.
4
+ */
5
+ import type { BrowseSession } from '../session.js';
6
+ export declare function fillSecret(session: BrowseSession, fillRef: string, intentId: string): Promise<void>;
7
+ //# sourceMappingURL=fill-secret.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"fill-secret.d.ts","sourceRoot":"","sources":["../../src/commands/fill-secret.ts"],"names":[],"mappings":"AAAA;;;GAGG;AAUH,OAAO,KAAK,EAAE,aAAa,EAAE,MAAM,eAAe,CAAC;AA8InD,wBAAsB,UAAU,CAC9B,OAAO,EAAE,aAAa,EACtB,OAAO,EAAE,MAAM,EACf,QAAQ,EAAE,MAAM,GACf,OAAO,CAAC,IAAI,CAAC,CAmUf"}