pi-agent-browser-native 0.2.48 → 0.2.49

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 (185) hide show
  1. package/CHANGELOG.md +17 -0
  2. package/README.md +16 -6
  3. package/dist/extensions/agent-browser/index.js +785 -0
  4. package/dist/extensions/agent-browser/lib/argv-descriptor.js +71 -0
  5. package/dist/extensions/agent-browser/lib/argv-grammar.js +121 -0
  6. package/dist/extensions/agent-browser/lib/bash-guard.js +190 -0
  7. package/dist/extensions/agent-browser/lib/command-policy.js +85 -0
  8. package/dist/extensions/agent-browser/lib/command-taxonomy.js +302 -0
  9. package/dist/extensions/agent-browser/lib/config-policy.js +686 -0
  10. package/dist/extensions/agent-browser/lib/config.js +122 -0
  11. package/dist/extensions/agent-browser/lib/electron/cdp.js +51 -0
  12. package/dist/extensions/agent-browser/lib/electron/cleanup.js +212 -0
  13. package/dist/extensions/agent-browser/lib/electron/discovery.js +633 -0
  14. package/dist/extensions/agent-browser/lib/electron/launch.js +351 -0
  15. package/{extensions/agent-browser/lib/electron/text.ts → dist/extensions/agent-browser/lib/electron/text.js} +5 -5
  16. package/dist/extensions/agent-browser/lib/executable-path.js +20 -0
  17. package/dist/extensions/agent-browser/lib/fs-utils.js +18 -0
  18. package/dist/extensions/agent-browser/lib/input-modes/electron.js +165 -0
  19. package/dist/extensions/agent-browser/lib/input-modes/job.js +519 -0
  20. package/dist/extensions/agent-browser/lib/input-modes/lookups.js +440 -0
  21. package/dist/extensions/agent-browser/lib/input-modes/params.js +164 -0
  22. package/dist/extensions/agent-browser/lib/input-modes/semantic-action.js +119 -0
  23. package/dist/extensions/agent-browser/lib/input-modes/shared.js +42 -0
  24. package/dist/extensions/agent-browser/lib/input-modes/types.js +21 -0
  25. package/dist/extensions/agent-browser/lib/input-modes.js +10 -0
  26. package/dist/extensions/agent-browser/lib/json-schema.js +58 -0
  27. package/dist/extensions/agent-browser/lib/launch-scoped-flags.js +59 -0
  28. package/dist/extensions/agent-browser/lib/navigation-policy.js +83 -0
  29. package/dist/extensions/agent-browser/lib/orchestration/batch-stdin.js +62 -0
  30. package/dist/extensions/agent-browser/lib/orchestration/browser-run/artifact-paths.js +39 -0
  31. package/dist/extensions/agent-browser/lib/orchestration/browser-run/click-dispatch.js +276 -0
  32. package/dist/extensions/agent-browser/lib/orchestration/browser-run/diagnostics.js +909 -0
  33. package/dist/extensions/agent-browser/lib/orchestration/browser-run/final-result.js +443 -0
  34. package/dist/extensions/agent-browser/lib/orchestration/browser-run/index.js +47 -0
  35. package/dist/extensions/agent-browser/lib/orchestration/browser-run/prepare/direct-anchor-download.js +141 -0
  36. package/dist/extensions/agent-browser/lib/orchestration/browser-run/prepare/network-page-filter.js +108 -0
  37. package/dist/extensions/agent-browser/lib/orchestration/browser-run/prepare/scroll-shims.js +112 -0
  38. package/dist/extensions/agent-browser/lib/orchestration/browser-run/prepare/snapshot-filter.js +158 -0
  39. package/dist/extensions/agent-browser/lib/orchestration/browser-run/prepare/wait-timeouts.js +54 -0
  40. package/dist/extensions/agent-browser/lib/orchestration/browser-run/prepare.js +762 -0
  41. package/dist/extensions/agent-browser/lib/orchestration/browser-run/process-output.js +491 -0
  42. package/dist/extensions/agent-browser/lib/orchestration/browser-run/prompt-guards.js +40 -0
  43. package/dist/extensions/agent-browser/lib/orchestration/browser-run/session-artifacts.js +5 -0
  44. package/dist/extensions/agent-browser/lib/orchestration/browser-run/session-state.js +731 -0
  45. package/dist/extensions/agent-browser/lib/orchestration/browser-run/types.js +1 -0
  46. package/dist/extensions/agent-browser/lib/orchestration/electron-host/index.js +718 -0
  47. package/dist/extensions/agent-browser/lib/orchestration/input-plan.js +247 -0
  48. package/dist/extensions/agent-browser/lib/orchestration/output-file.js +68 -0
  49. package/{extensions/agent-browser/lib/parsing.ts → dist/extensions/agent-browser/lib/parsing.js} +12 -11
  50. package/dist/extensions/agent-browser/lib/pi-tool-rendering.js +241 -0
  51. package/dist/extensions/agent-browser/lib/playbook.js +121 -0
  52. package/dist/extensions/agent-browser/lib/process.js +448 -0
  53. package/dist/extensions/agent-browser/lib/prompt-policy.js +91 -0
  54. package/dist/extensions/agent-browser/lib/results/action-recommendations.js +220 -0
  55. package/dist/extensions/agent-browser/lib/results/artifact-manifest.js +111 -0
  56. package/{extensions/agent-browser/lib/results/artifact-state.ts → dist/extensions/agent-browser/lib/results/artifact-state.js} +4 -8
  57. package/dist/extensions/agent-browser/lib/results/categories.js +76 -0
  58. package/dist/extensions/agent-browser/lib/results/confirmation.js +63 -0
  59. package/dist/extensions/agent-browser/lib/results/contracts.js +8 -0
  60. package/dist/extensions/agent-browser/lib/results/editable-ref-evidence.js +74 -0
  61. package/dist/extensions/agent-browser/lib/results/envelope.js +166 -0
  62. package/dist/extensions/agent-browser/lib/results/network-routes.js +92 -0
  63. package/dist/extensions/agent-browser/lib/results/network.js +73 -0
  64. package/dist/extensions/agent-browser/lib/results/next-actions.js +72 -0
  65. package/dist/extensions/agent-browser/lib/results/presentation/artifacts.js +515 -0
  66. package/dist/extensions/agent-browser/lib/results/presentation/batch.js +397 -0
  67. package/dist/extensions/agent-browser/lib/results/presentation/browser-profile-recovery.js +55 -0
  68. package/dist/extensions/agent-browser/lib/results/presentation/common.js +46 -0
  69. package/dist/extensions/agent-browser/lib/results/presentation/content.js +24 -0
  70. package/dist/extensions/agent-browser/lib/results/presentation/diagnostics.js +960 -0
  71. package/dist/extensions/agent-browser/lib/results/presentation/errors.js +205 -0
  72. package/dist/extensions/agent-browser/lib/results/presentation/large-output.js +134 -0
  73. package/dist/extensions/agent-browser/lib/results/presentation/navigation.js +159 -0
  74. package/dist/extensions/agent-browser/lib/results/presentation/registry.js +216 -0
  75. package/dist/extensions/agent-browser/lib/results/presentation/semantic-action.js +104 -0
  76. package/dist/extensions/agent-browser/lib/results/presentation/skills.js +152 -0
  77. package/dist/extensions/agent-browser/lib/results/presentation.js +177 -0
  78. package/dist/extensions/agent-browser/lib/results/recovery-actions.js +107 -0
  79. package/dist/extensions/agent-browser/lib/results/recovery-next-actions.js +50 -0
  80. package/dist/extensions/agent-browser/lib/results/selector-recovery.js +225 -0
  81. package/{extensions/agent-browser/lib/results/shared.ts → dist/extensions/agent-browser/lib/results/shared.js} +0 -1
  82. package/dist/extensions/agent-browser/lib/results/snapshot-high-value-controls.js +208 -0
  83. package/dist/extensions/agent-browser/lib/results/snapshot-refs.js +78 -0
  84. package/dist/extensions/agent-browser/lib/results/snapshot-segments.js +331 -0
  85. package/dist/extensions/agent-browser/lib/results/snapshot-spill.js +40 -0
  86. package/dist/extensions/agent-browser/lib/results/snapshot.js +264 -0
  87. package/dist/extensions/agent-browser/lib/results/text.js +40 -0
  88. package/{extensions/agent-browser/lib/results.ts → dist/extensions/agent-browser/lib/results.js} +2 -32
  89. package/dist/extensions/agent-browser/lib/runtime.js +816 -0
  90. package/dist/extensions/agent-browser/lib/session-page-state.js +411 -0
  91. package/dist/extensions/agent-browser/lib/string-enum-schema.js +13 -0
  92. package/dist/extensions/agent-browser/lib/temp.js +498 -0
  93. package/dist/extensions/agent-browser/lib/web-search.js +562 -0
  94. package/docs/RELEASE.md +22 -11
  95. package/docs/SUPPORT_MATRIX.md +4 -3
  96. package/package.json +9 -5
  97. package/scripts/config.mjs +8 -2
  98. package/scripts/doctor.mjs +8 -7
  99. package/extensions/agent-browser/index.ts +0 -961
  100. package/extensions/agent-browser/lib/argv-descriptor.ts +0 -90
  101. package/extensions/agent-browser/lib/argv-grammar.ts +0 -128
  102. package/extensions/agent-browser/lib/bash-guard.ts +0 -205
  103. package/extensions/agent-browser/lib/command-policy.ts +0 -71
  104. package/extensions/agent-browser/lib/command-taxonomy.ts +0 -336
  105. package/extensions/agent-browser/lib/config-policy.js +0 -690
  106. package/extensions/agent-browser/lib/config.ts +0 -211
  107. package/extensions/agent-browser/lib/electron/cdp.ts +0 -69
  108. package/extensions/agent-browser/lib/electron/cleanup.ts +0 -235
  109. package/extensions/agent-browser/lib/electron/discovery.ts +0 -710
  110. package/extensions/agent-browser/lib/electron/launch.ts +0 -499
  111. package/extensions/agent-browser/lib/executable-path.ts +0 -19
  112. package/extensions/agent-browser/lib/fs-utils.ts +0 -18
  113. package/extensions/agent-browser/lib/input-modes/electron.ts +0 -170
  114. package/extensions/agent-browser/lib/input-modes/job.ts +0 -527
  115. package/extensions/agent-browser/lib/input-modes/lookups.ts +0 -447
  116. package/extensions/agent-browser/lib/input-modes/params.ts +0 -205
  117. package/extensions/agent-browser/lib/input-modes/semantic-action.ts +0 -127
  118. package/extensions/agent-browser/lib/input-modes/shared.ts +0 -46
  119. package/extensions/agent-browser/lib/input-modes/types.ts +0 -225
  120. package/extensions/agent-browser/lib/input-modes.ts +0 -45
  121. package/extensions/agent-browser/lib/json-schema.ts +0 -73
  122. package/extensions/agent-browser/lib/launch-scoped-flags.ts +0 -67
  123. package/extensions/agent-browser/lib/navigation-policy.ts +0 -95
  124. package/extensions/agent-browser/lib/orchestration/batch-stdin.ts +0 -65
  125. package/extensions/agent-browser/lib/orchestration/browser-run/artifact-paths.ts +0 -44
  126. package/extensions/agent-browser/lib/orchestration/browser-run/click-dispatch.ts +0 -280
  127. package/extensions/agent-browser/lib/orchestration/browser-run/diagnostics.ts +0 -914
  128. package/extensions/agent-browser/lib/orchestration/browser-run/final-result.ts +0 -521
  129. package/extensions/agent-browser/lib/orchestration/browser-run/index.ts +0 -53
  130. package/extensions/agent-browser/lib/orchestration/browser-run/prepare/direct-anchor-download.ts +0 -158
  131. package/extensions/agent-browser/lib/orchestration/browser-run/prepare/network-page-filter.ts +0 -116
  132. package/extensions/agent-browser/lib/orchestration/browser-run/prepare/scroll-shims.ts +0 -147
  133. package/extensions/agent-browser/lib/orchestration/browser-run/prepare/snapshot-filter.ts +0 -183
  134. package/extensions/agent-browser/lib/orchestration/browser-run/prepare/wait-timeouts.ts +0 -58
  135. package/extensions/agent-browser/lib/orchestration/browser-run/prepare.ts +0 -847
  136. package/extensions/agent-browser/lib/orchestration/browser-run/process-output.ts +0 -559
  137. package/extensions/agent-browser/lib/orchestration/browser-run/prompt-guards.ts +0 -47
  138. package/extensions/agent-browser/lib/orchestration/browser-run/session-artifacts.ts +0 -8
  139. package/extensions/agent-browser/lib/orchestration/browser-run/session-state.ts +0 -868
  140. package/extensions/agent-browser/lib/orchestration/browser-run/types.ts +0 -565
  141. package/extensions/agent-browser/lib/orchestration/electron-host/index.ts +0 -855
  142. package/extensions/agent-browser/lib/orchestration/input-plan.ts +0 -375
  143. package/extensions/agent-browser/lib/orchestration/output-file.ts +0 -86
  144. package/extensions/agent-browser/lib/pi-tool-rendering.ts +0 -267
  145. package/extensions/agent-browser/lib/playbook.ts +0 -142
  146. package/extensions/agent-browser/lib/process.ts +0 -516
  147. package/extensions/agent-browser/lib/prompt-policy.ts +0 -105
  148. package/extensions/agent-browser/lib/results/action-recommendations.ts +0 -264
  149. package/extensions/agent-browser/lib/results/artifact-manifest.ts +0 -111
  150. package/extensions/agent-browser/lib/results/categories.ts +0 -106
  151. package/extensions/agent-browser/lib/results/confirmation.ts +0 -76
  152. package/extensions/agent-browser/lib/results/contracts.ts +0 -241
  153. package/extensions/agent-browser/lib/results/editable-ref-evidence.ts +0 -72
  154. package/extensions/agent-browser/lib/results/envelope.ts +0 -195
  155. package/extensions/agent-browser/lib/results/network-routes.ts +0 -83
  156. package/extensions/agent-browser/lib/results/network.ts +0 -78
  157. package/extensions/agent-browser/lib/results/next-actions.ts +0 -117
  158. package/extensions/agent-browser/lib/results/presentation/artifacts.ts +0 -588
  159. package/extensions/agent-browser/lib/results/presentation/batch.ts +0 -450
  160. package/extensions/agent-browser/lib/results/presentation/browser-profile-recovery.ts +0 -67
  161. package/extensions/agent-browser/lib/results/presentation/common.ts +0 -53
  162. package/extensions/agent-browser/lib/results/presentation/content.ts +0 -36
  163. package/extensions/agent-browser/lib/results/presentation/diagnostics.ts +0 -923
  164. package/extensions/agent-browser/lib/results/presentation/errors.ts +0 -227
  165. package/extensions/agent-browser/lib/results/presentation/large-output.ts +0 -182
  166. package/extensions/agent-browser/lib/results/presentation/navigation.ts +0 -184
  167. package/extensions/agent-browser/lib/results/presentation/registry.ts +0 -242
  168. package/extensions/agent-browser/lib/results/presentation/semantic-action.ts +0 -131
  169. package/extensions/agent-browser/lib/results/presentation/skills.ts +0 -143
  170. package/extensions/agent-browser/lib/results/presentation.ts +0 -257
  171. package/extensions/agent-browser/lib/results/recovery-actions.ts +0 -139
  172. package/extensions/agent-browser/lib/results/recovery-next-actions.ts +0 -71
  173. package/extensions/agent-browser/lib/results/selector-recovery.ts +0 -320
  174. package/extensions/agent-browser/lib/results/snapshot-high-value-controls.ts +0 -273
  175. package/extensions/agent-browser/lib/results/snapshot-refs.ts +0 -100
  176. package/extensions/agent-browser/lib/results/snapshot-segments.ts +0 -366
  177. package/extensions/agent-browser/lib/results/snapshot-spill.ts +0 -63
  178. package/extensions/agent-browser/lib/results/snapshot.ts +0 -329
  179. package/extensions/agent-browser/lib/results/text.ts +0 -40
  180. package/extensions/agent-browser/lib/runtime.ts +0 -988
  181. package/extensions/agent-browser/lib/session-page-state.ts +0 -512
  182. package/extensions/agent-browser/lib/string-enum-schema.ts +0 -20
  183. package/extensions/agent-browser/lib/temp.ts +0 -577
  184. package/extensions/agent-browser/lib/web-search.ts +0 -728
  185. /package/{extensions/agent-browser/lib/orchestration/browser-run.ts → dist/extensions/agent-browser/lib/orchestration/browser-run.js} +0 -0
@@ -0,0 +1,247 @@
1
+ import { parseArgvDescriptor } from "../argv-descriptor.js";
2
+ import { validateToolArgs, redactInvocationArgs, redactSensitiveText } from "../runtime.js";
3
+ import { buildAgentBrowserResultCategoryDetails } from "../results/categories.js";
4
+ import { compileAgentBrowserElectron, compileAgentBrowserJob, compileAgentBrowserNetworkSourceLookup, compileAgentBrowserQaPreset, compileAgentBrowserSemanticAction, compileAgentBrowserSourceLookup, redactNetworkSourceLookupArgs, redactNetworkSourceLookupUrl, } from "../input-modes.js";
5
+ function redactCompiledElectron(compiled) {
6
+ if (!compiled)
7
+ return undefined;
8
+ if (compiled.action === "list") {
9
+ return { ...compiled, query: compiled.query ? redactSensitiveText(compiled.query) : undefined };
10
+ }
11
+ if (compiled.action === "launch") {
12
+ return { ...compiled, appArgs: compiled.appArgs ? redactInvocationArgs(compiled.appArgs) : undefined };
13
+ }
14
+ return { ...compiled };
15
+ }
16
+ function redactCompiledJob(compiled) {
17
+ const redactedSteps = compiled?.steps.map((step) => ({ ...step, args: redactInvocationArgs(step.args) }));
18
+ return compiled && redactedSteps
19
+ ? { ...compiled, stdin: JSON.stringify(redactedSteps.map((step) => step.args)), steps: redactedSteps }
20
+ : undefined;
21
+ }
22
+ function redactCompiledSourceLookup(compiled) {
23
+ const redactedSteps = compiled?.steps.map((step) => ({ ...step, args: redactInvocationArgs(step.args) }));
24
+ return compiled && redactedSteps
25
+ ? { ...compiled, stdin: JSON.stringify(redactedSteps.map((step) => step.args)), steps: redactedSteps }
26
+ : undefined;
27
+ }
28
+ function redactCompiledNetworkSourceLookup(compiled) {
29
+ const redactedSteps = compiled?.steps.map((step) => ({ ...step, args: redactNetworkSourceLookupArgs(step.args) }));
30
+ return compiled && redactedSteps
31
+ ? {
32
+ ...compiled,
33
+ args: redactNetworkSourceLookupArgs(compiled.args),
34
+ query: {
35
+ ...compiled.query,
36
+ filter: redactNetworkSourceLookupUrl(compiled.query.filter),
37
+ url: redactNetworkSourceLookupUrl(compiled.query.url),
38
+ },
39
+ stdin: JSON.stringify(redactedSteps.map((step) => step.args)),
40
+ steps: redactedSteps,
41
+ }
42
+ : undefined;
43
+ }
44
+ function normalizeExplicitEvalStdinArgs(args, stdin) {
45
+ if (stdin !== undefined) {
46
+ return { args, stdin };
47
+ }
48
+ const descriptor = parseArgvDescriptor(args);
49
+ if (descriptor.commandInfo.command !== "eval") {
50
+ return { args, stdin };
51
+ }
52
+ const stdinIndex = descriptor.commandTokens.indexOf("--stdin");
53
+ if (stdinIndex < 0 || stdinIndex >= descriptor.commandTokens.length - 1) {
54
+ return { args, stdin };
55
+ }
56
+ const commandStartIndex = args.length - descriptor.commandTokens.length;
57
+ const stdinValue = descriptor.commandTokens.slice(stdinIndex + 1).join(" ");
58
+ return {
59
+ args: [...args.slice(0, commandStartIndex), ...descriptor.commandTokens.slice(0, stdinIndex + 1)],
60
+ stdin: stdinValue,
61
+ };
62
+ }
63
+ export function resolveAgentBrowserInput(options) {
64
+ const { getBatchPreflightValidationError, managedSessionActive, params } = options;
65
+ const semanticActionResult = params.semanticAction === undefined ? {} : compileAgentBrowserSemanticAction(params.semanticAction);
66
+ const jobResult = params.job === undefined ? {} : compileAgentBrowserJob(params.job);
67
+ const qaResult = params.qa === undefined ? {} : compileAgentBrowserQaPreset(params.qa);
68
+ const sourceLookupResult = params.sourceLookup === undefined ? {} : compileAgentBrowserSourceLookup(params.sourceLookup);
69
+ const networkSourceLookupResult = params.networkSourceLookup === undefined ? {} : compileAgentBrowserNetworkSourceLookup(params.networkSourceLookup);
70
+ const electronResult = params.electron === undefined ? {} : compileAgentBrowserElectron(params.electron);
71
+ const hasExplicitArgs = Array.isArray(params.args);
72
+ const explicitInputModes = [
73
+ hasExplicitArgs,
74
+ Boolean(semanticActionResult.compiled),
75
+ Boolean(jobResult.compiled),
76
+ Boolean(qaResult.compiled),
77
+ Boolean(sourceLookupResult.compiled),
78
+ Boolean(networkSourceLookupResult.compiled),
79
+ Boolean(electronResult.compiled),
80
+ ].filter(Boolean).length;
81
+ const inputModeError = explicitInputModes !== 1
82
+ ? "Provide exactly one of args, semanticAction, job, qa, sourceLookup, networkSourceLookup, or electron."
83
+ : undefined;
84
+ const compiledSemanticAction = semanticActionResult.compiled;
85
+ const compiledQaPreset = qaResult.compiled;
86
+ const compiledSourceLookup = sourceLookupResult.compiled;
87
+ const compiledNetworkSourceLookup = networkSourceLookupResult.compiled;
88
+ const compiledElectron = electronResult.compiled;
89
+ const compiledJob = jobResult.compiled ?? compiledQaPreset;
90
+ const compiledGeneratedBatch = compiledNetworkSourceLookup ?? compiledSourceLookup ?? compiledJob;
91
+ const normalizedExplicitArgs = normalizeExplicitEvalStdinArgs(params.args ?? [], params.stdin);
92
+ const toolArgs = compiledElectron ? [] : compiledSemanticAction?.args ?? compiledGeneratedBatch?.args ?? normalizedExplicitArgs.args;
93
+ const toolStdin = compiledGeneratedBatch?.stdin ?? normalizedExplicitArgs.stdin;
94
+ const redactedArgs = redactInvocationArgs(toolArgs);
95
+ const generatedStdinError = params.stdin !== undefined
96
+ ? compiledGeneratedBatch
97
+ ? "Do not provide stdin with job, qa, sourceLookup, or networkSourceLookup; those modes generate their own batch stdin."
98
+ : compiledElectron
99
+ ? "Do not provide stdin with electron; electron mode is host-only or manages its own input."
100
+ : undefined
101
+ : undefined;
102
+ const outputPathError = params.outputPath !== undefined && (typeof params.outputPath !== "string" || params.outputPath.trim().length === 0)
103
+ ? "outputPath must be a non-empty string when provided."
104
+ : undefined;
105
+ const timeoutMsError = params.timeoutMs !== undefined && (typeof params.timeoutMs !== "number" || !Number.isSafeInteger(params.timeoutMs) || params.timeoutMs <= 0)
106
+ ? "timeoutMs must be a positive integer when provided."
107
+ : compiledElectron && params.timeoutMs !== undefined
108
+ ? "Use electron.timeoutMs for electron actions; top-level timeoutMs applies only to browser CLI subprocess calls."
109
+ : undefined;
110
+ const attachedQaSessionError = compiledQaPreset?.checks.attached
111
+ ? params.sessionMode === "fresh"
112
+ ? "qa.attached cannot be used with sessionMode=fresh; attach or launch a session first, then run qa.attached with the current session."
113
+ : !managedSessionActive
114
+ ? "qa.attached requires an active attached session. Run electron.launch or connect to an Electron debug port first."
115
+ : undefined
116
+ : undefined;
117
+ const validationError = semanticActionResult.error
118
+ ?? jobResult.error
119
+ ?? qaResult.error
120
+ ?? sourceLookupResult.error
121
+ ?? networkSourceLookupResult.error
122
+ ?? electronResult.error
123
+ ?? inputModeError
124
+ ?? generatedStdinError
125
+ ?? outputPathError
126
+ ?? timeoutMsError
127
+ ?? attachedQaSessionError
128
+ ?? (compiledElectron ? undefined : validateToolArgs(toolArgs) ?? getBatchPreflightValidationError(toolArgs, toolStdin));
129
+ const redactedCompiledJob = redactCompiledJob(compiledJob);
130
+ const redactedCompiledSemanticAction = compiledSemanticAction
131
+ ? { ...compiledSemanticAction, args: redactInvocationArgs(compiledSemanticAction.args) }
132
+ : undefined;
133
+ const attemptedKind = compiledElectron
134
+ ? "electron"
135
+ : compiledNetworkSourceLookup
136
+ ? "networkSourceLookup"
137
+ : compiledSourceLookup
138
+ ? "sourceLookup"
139
+ : compiledQaPreset
140
+ ? "qa"
141
+ : jobResult.compiled
142
+ ? "job"
143
+ : compiledSemanticAction
144
+ ? "semanticAction"
145
+ : hasExplicitArgs
146
+ ? "args"
147
+ : undefined;
148
+ const redactedCompiledElectron = redactCompiledElectron(compiledElectron);
149
+ const redactedCompiledNetworkSourceLookup = redactCompiledNetworkSourceLookup(compiledNetworkSourceLookup);
150
+ const redactedCompiledQaPreset = compiledQaPreset && redactedCompiledJob ? { ...redactedCompiledJob, checks: compiledQaPreset.checks } : undefined;
151
+ const redactedCompiledSourceLookup = redactCompiledSourceLookup(compiledSourceLookup);
152
+ const resolvedBase = { redactedArgs, toolArgs, toolStdin };
153
+ if (validationError) {
154
+ return {
155
+ ...resolvedBase,
156
+ attemptedKind,
157
+ compiledElectron,
158
+ compiledGeneratedBatch,
159
+ compiledJob,
160
+ compiledNetworkSourceLookup,
161
+ compiledQaPreset,
162
+ compiledSemanticAction,
163
+ compiledSourceLookup,
164
+ kind: "invalid",
165
+ redactedCompiledElectron,
166
+ redactedCompiledJob,
167
+ redactedCompiledNetworkSourceLookup,
168
+ redactedCompiledQaPreset,
169
+ redactedCompiledSemanticAction,
170
+ redactedCompiledSourceLookup,
171
+ status: "invalid",
172
+ validationError,
173
+ };
174
+ }
175
+ if (compiledElectron && redactedCompiledElectron) {
176
+ return { ...resolvedBase, compiledElectron, kind: "electron", redactedCompiledElectron, status: "valid" };
177
+ }
178
+ if (compiledNetworkSourceLookup && redactedCompiledNetworkSourceLookup) {
179
+ return {
180
+ ...resolvedBase,
181
+ compiledGeneratedBatch: compiledNetworkSourceLookup,
182
+ compiledNetworkSourceLookup,
183
+ kind: "networkSourceLookup",
184
+ redactedCompiledNetworkSourceLookup,
185
+ status: "valid",
186
+ };
187
+ }
188
+ if (compiledSourceLookup && redactedCompiledSourceLookup) {
189
+ return {
190
+ ...resolvedBase,
191
+ compiledGeneratedBatch: compiledSourceLookup,
192
+ compiledSourceLookup,
193
+ kind: "sourceLookup",
194
+ redactedCompiledSourceLookup,
195
+ status: "valid",
196
+ };
197
+ }
198
+ if (compiledQaPreset && redactedCompiledJob && redactedCompiledQaPreset) {
199
+ return {
200
+ ...resolvedBase,
201
+ compiledGeneratedBatch: compiledQaPreset,
202
+ compiledJob: compiledQaPreset,
203
+ compiledQaPreset,
204
+ kind: "qa",
205
+ redactedCompiledJob,
206
+ redactedCompiledQaPreset,
207
+ status: "valid",
208
+ };
209
+ }
210
+ if (jobResult.compiled && redactedCompiledJob) {
211
+ return {
212
+ ...resolvedBase,
213
+ compiledGeneratedBatch: jobResult.compiled,
214
+ compiledJob: jobResult.compiled,
215
+ kind: "job",
216
+ redactedCompiledJob,
217
+ status: "valid",
218
+ };
219
+ }
220
+ if (compiledSemanticAction && redactedCompiledSemanticAction) {
221
+ return { ...resolvedBase, compiledSemanticAction, kind: "semanticAction", redactedCompiledSemanticAction, status: "valid" };
222
+ }
223
+ return { ...resolvedBase, kind: "args", status: "valid" };
224
+ }
225
+ export function buildValidationFailureResult(input) {
226
+ const validationError = input.validationError ?? "Invalid agent_browser input.";
227
+ return {
228
+ content: [{ type: "text", text: validationError }],
229
+ details: {
230
+ args: input.redactedArgs,
231
+ compiledElectron: input.redactedCompiledElectron,
232
+ compiledJob: input.redactedCompiledJob,
233
+ compiledQaPreset: input.redactedCompiledQaPreset,
234
+ compiledSourceLookup: input.redactedCompiledSourceLookup,
235
+ compiledNetworkSourceLookup: input.redactedCompiledNetworkSourceLookup,
236
+ compiledSemanticAction: input.redactedCompiledSemanticAction,
237
+ ...buildAgentBrowserResultCategoryDetails({
238
+ args: input.redactedArgs,
239
+ errorText: validationError,
240
+ succeeded: false,
241
+ validationError,
242
+ }),
243
+ validationError,
244
+ },
245
+ isError: true,
246
+ };
247
+ }
@@ -0,0 +1,68 @@
1
+ import { mkdir, writeFile } from "node:fs/promises";
2
+ import { dirname, isAbsolute, resolve } from "node:path";
3
+ import { isRecord } from "../parsing.js";
4
+ function normalizeRequestedOutputPath(path) {
5
+ return path.startsWith("@") ? path.slice(1) : path;
6
+ }
7
+ function getTextContent(result) {
8
+ return result.content
9
+ ?.filter((item) => item.type === "text")
10
+ .map((item) => item.text)
11
+ .join("\n\n") ?? "";
12
+ }
13
+ function getOutputPayload(result) {
14
+ const details = isRecord(result.details) ? result.details : undefined;
15
+ if (details && details.data !== undefined)
16
+ return { source: "details.data", value: details.data };
17
+ return { source: "content.text", value: getTextContent(result) };
18
+ }
19
+ function serializeOutputPayload(value) {
20
+ return typeof value === "string" ? value : `${JSON.stringify(value, null, 2)}\n`;
21
+ }
22
+ function appendOutputFileNotice(result, message) {
23
+ const content = [...(result.content ?? [])];
24
+ if (content[0]?.type === "text") {
25
+ content[0] = { ...content[0], text: `${content[0].text}\n\n${message}` };
26
+ return content;
27
+ }
28
+ return [{ type: "text", text: message }, ...content];
29
+ }
30
+ export async function applyAgentBrowserOutputPath(options) {
31
+ if (!options.outputPath)
32
+ return options.result;
33
+ if (options.result.isError || (isRecord(options.result.details) && options.result.details.resultCategory === "failure"))
34
+ return options.result;
35
+ const requestedPath = normalizeRequestedOutputPath(options.outputPath);
36
+ const absolutePath = isAbsolute(requestedPath) ? requestedPath : resolve(options.cwd, requestedPath);
37
+ const payload = getOutputPayload(options.result);
38
+ try {
39
+ const serialized = serializeOutputPayload(payload.value);
40
+ await mkdir(dirname(absolutePath), { recursive: true });
41
+ await writeFile(absolutePath, serialized, "utf8");
42
+ const bytes = Buffer.byteLength(serialized, "utf8");
43
+ const outputFile = { absolutePath, bytes, path: requestedPath, source: payload.source, status: "saved" };
44
+ const details = isRecord(options.result.details) ? { ...options.result.details, outputFile } : { outputFile };
45
+ return {
46
+ ...options.result,
47
+ content: options.preserveTextContent ? options.result.content : appendOutputFileNotice(options.result, `Output file: ${requestedPath} (${bytes} bytes from ${payload.source}).`),
48
+ details,
49
+ };
50
+ }
51
+ catch (error) {
52
+ const message = error instanceof Error ? error.message : String(error);
53
+ const outputFile = { absolutePath, error: message, path: requestedPath, source: payload.source, status: "failed" };
54
+ const details = isRecord(options.result.details)
55
+ ? (() => {
56
+ const rest = { ...options.result.details };
57
+ delete rest.successCategory;
58
+ return { ...rest, failureCategory: rest.failureCategory ?? "upstream-error", outputFile, resultCategory: "failure" };
59
+ })()
60
+ : { failureCategory: "upstream-error", outputFile, resultCategory: "failure" };
61
+ return {
62
+ ...options.result,
63
+ content: options.preserveTextContent ? options.result.content : appendOutputFileNotice(options.result, `Output file failed: ${requestedPath} (${message}).`),
64
+ details,
65
+ isError: true,
66
+ };
67
+ }
68
+ }
@@ -5,16 +5,17 @@
5
5
  * Usage: Imported by agent-browser wrapper modules that parse untyped JSON, persisted state, or environment variables.
6
6
  * Invariants/Assumptions: Arrays intentionally count as records to preserve existing object-boundary semantics, and positive integers must be safe base-10 integer strings greater than zero.
7
7
  */
8
-
9
- export function isRecord(value: unknown): value is Record<string, unknown> {
10
- return typeof value === "object" && value !== null;
8
+ export function isRecord(value) {
9
+ return typeof value === "object" && value !== null;
11
10
  }
12
-
13
- export function parsePositiveInteger(rawValue: string | undefined): number | undefined {
14
- if (typeof rawValue !== "string") return undefined;
15
- const normalizedValue = rawValue.trim();
16
- if (!/^\d+$/.test(normalizedValue)) return undefined;
17
- const parsedValue = Number(normalizedValue);
18
- if (!Number.isSafeInteger(parsedValue) || parsedValue <= 0) return undefined;
19
- return parsedValue;
11
+ export function parsePositiveInteger(rawValue) {
12
+ if (typeof rawValue !== "string")
13
+ return undefined;
14
+ const normalizedValue = rawValue.trim();
15
+ if (!/^\d+$/.test(normalizedValue))
16
+ return undefined;
17
+ const parsedValue = Number(normalizedValue);
18
+ if (!Number.isSafeInteger(parsedValue) || parsedValue <= 0)
19
+ return undefined;
20
+ return parsedValue;
20
21
  }
@@ -0,0 +1,241 @@
1
+ import { getKeybindings, Text, truncateToWidth } from "@earendil-works/pi-tui";
2
+ import { compileAgentBrowserElectron, compileAgentBrowserJob, compileAgentBrowserNetworkSourceLookup, compileAgentBrowserQaPreset, compileAgentBrowserSemanticAction, compileAgentBrowserSourceLookup, } from "./input-modes.js";
3
+ import { isRecord } from "./parsing.js";
4
+ import { redactInvocationArgs } from "./runtime.js";
5
+ const TUI_INVOCATION_PREVIEW_MAX_CHARS = 160;
6
+ const TUI_COLLAPSED_OUTPUT_MAX_LINES = 12;
7
+ const ANSI_CONTROL_SEQUENCE_PATTERN = /\x1B(?:\][^\x07\x1B]*(?:\x07|\x1B\\)|\[[0-?]*[ -/]*[@-~]|P[^\x1B]*(?:\x1B\\)|_[^\x1B]*(?:\x1B\\)|\^[^\x1B]*(?:\x1B\\)|[@-Z\\-_])/g;
8
+ const JSON_TOKEN_PATTERN = /"(?:\\.|[^"\\])*"(?=\s*:)|"(?:\\.|[^"\\])*"|-?\d+(?:\.\d+)?(?:[eE][+-]?\d+)?|true|false|null|[{}\[\],:]/g;
9
+ const UNSAFE_DISPLAY_CONTROL_PATTERN = /[\x00-\x08\x0B\x0C\x0E-\x1F\x7F\x80-\x9F]/g;
10
+ function sanitizeDisplayText(value) {
11
+ return value
12
+ .replace(ANSI_CONTROL_SEQUENCE_PATTERN, "")
13
+ .replace(/\r/g, "")
14
+ .replace(UNSAFE_DISPLAY_CONTROL_PATTERN, "�");
15
+ }
16
+ function replaceTabsForDisplay(value) {
17
+ return value.replaceAll("\t", " ");
18
+ }
19
+ function trimTrailingBlankLines(lines) {
20
+ let end = lines.length;
21
+ while (end > 0 && lines[end - 1].trim().length === 0) {
22
+ end -= 1;
23
+ }
24
+ return lines.slice(0, end);
25
+ }
26
+ function isJsonDocumentText(value) {
27
+ const trimmed = value.trim();
28
+ if (!trimmed.startsWith("{") && !trimmed.startsWith("["))
29
+ return false;
30
+ try {
31
+ JSON.parse(trimmed);
32
+ return true;
33
+ }
34
+ catch {
35
+ return false;
36
+ }
37
+ }
38
+ function colorizeJsonLine(line, theme) {
39
+ let output = "";
40
+ let cursor = 0;
41
+ for (const match of line.matchAll(JSON_TOKEN_PATTERN)) {
42
+ const token = match[0];
43
+ const index = match.index ?? 0;
44
+ output += line.slice(cursor, index);
45
+ const color = token.startsWith('"')
46
+ ? /"\s*$/.test(token) && line.slice(index + token.length).trimStart().startsWith(":")
47
+ ? "syntaxVariable"
48
+ : "syntaxString"
49
+ : /^[{}\[\],:]$/.test(token)
50
+ ? "syntaxPunctuation"
51
+ : "syntaxType";
52
+ output += theme.fg(color, token);
53
+ cursor = index + token.length;
54
+ }
55
+ return output + line.slice(cursor);
56
+ }
57
+ function getPrimaryTextContent(result) {
58
+ const textContent = result.content.find((item) => item.type === "text");
59
+ return textContent?.type === "text" ? textContent.text : "";
60
+ }
61
+ function colorizeToolOutputLines(outputText, theme, isError) {
62
+ const normalizedLines = trimTrailingBlankLines(replaceTabsForDisplay(sanitizeDisplayText(outputText)).split("\n"));
63
+ const normalizedText = normalizedLines.join("\n");
64
+ if (normalizedText.length === 0)
65
+ return [];
66
+ const isJsonDocument = !isError && isJsonDocumentText(normalizedText);
67
+ return normalizedLines.map((line) => {
68
+ if (line.length === 0) {
69
+ return "";
70
+ }
71
+ if (isJsonDocument)
72
+ return colorizeJsonLine(line, theme);
73
+ return isError ? theme.fg("error", line) : theme.fg("toolOutput", line);
74
+ });
75
+ }
76
+ function formatExpandHint(theme) {
77
+ try {
78
+ const [key] = getKeybindings().getKeys("app.tools.expand");
79
+ if (key)
80
+ return `${theme.fg("dim", key)} ${theme.fg("muted", "to expand")}`;
81
+ }
82
+ catch {
83
+ // Fall through to the built-in default key when coding-agent keybindings are unavailable.
84
+ }
85
+ return `${theme.fg("dim", "ctrl+o")} ${theme.fg("muted", "to expand")}`;
86
+ }
87
+ function formatVisualTruncationNotice(remainingLines, totalLines, theme, width) {
88
+ const notice = `${theme.fg("muted", `... (${remainingLines} more lines, ${totalLines} total, `)}${formatExpandHint(theme)}${theme.fg("muted", ")")}`;
89
+ return truncateToWidth(notice, Math.max(0, width));
90
+ }
91
+ function getStructuredModeInvocation(input) {
92
+ if (Array.isArray(input.args))
93
+ return { rawArgs: input.args.filter((value) => typeof value === "string") };
94
+ if (input.semanticAction !== undefined)
95
+ return { mode: "semanticAction", rawArgs: compileAgentBrowserSemanticAction(input.semanticAction).compiled?.args ?? [] };
96
+ if (input.job !== undefined)
97
+ return { mode: "job", rawArgs: compileAgentBrowserJob(input.job).compiled?.args ?? [] };
98
+ if (input.qa !== undefined)
99
+ return { mode: "qa", rawArgs: compileAgentBrowserQaPreset(input.qa).compiled?.args ?? [] };
100
+ if (input.sourceLookup !== undefined)
101
+ return { mode: "sourceLookup", rawArgs: compileAgentBrowserSourceLookup(input.sourceLookup).compiled?.args ?? [] };
102
+ if (input.networkSourceLookup !== undefined)
103
+ return { mode: "networkSourceLookup", rawArgs: compileAgentBrowserNetworkSourceLookup(input.networkSourceLookup).compiled?.args ?? [] };
104
+ if (input.electron !== undefined) {
105
+ const electron = compileAgentBrowserElectron(input.electron);
106
+ return { mode: "electron", rawArgs: electron.compiled ? ["electron", electron.compiled.action] : [] };
107
+ }
108
+ return { rawArgs: [] };
109
+ }
110
+ function formatInvocationPreview(rawArgs) {
111
+ const redactedArgs = redactInvocationArgs(rawArgs);
112
+ const invocation = sanitizeDisplayText(redactedArgs.join(" ")).replace(/\s+/g, " ").trim();
113
+ return invocation.length > TUI_INVOCATION_PREVIEW_MAX_CHARS
114
+ ? `${invocation.slice(0, TUI_INVOCATION_PREVIEW_MAX_CHARS - 3)}...`
115
+ : invocation;
116
+ }
117
+ export function formatAgentBrowserRenderCall(args, theme) {
118
+ const input = isRecord(args) ? args : {};
119
+ const { mode, rawArgs } = getStructuredModeInvocation(input);
120
+ const invocationPreview = formatInvocationPreview(rawArgs);
121
+ let text = theme.fg("toolTitle", theme.bold("agent_browser"));
122
+ if (mode) {
123
+ text += ` ${theme.fg("accent", mode)}`;
124
+ if (invocationPreview.length > 0) {
125
+ text += ` ${theme.fg("dim", "→")} ${theme.fg("accent", invocationPreview)}`;
126
+ }
127
+ }
128
+ else if (invocationPreview.length > 0) {
129
+ text += ` ${theme.fg("accent", invocationPreview)}`;
130
+ }
131
+ if (input.sessionMode === "fresh") {
132
+ text += theme.fg("dim", " sessionMode=fresh");
133
+ }
134
+ if (typeof input.stdin === "string") {
135
+ text += theme.fg("dim", " + stdin");
136
+ }
137
+ return text;
138
+ }
139
+ export function formatAgentBrowserRenderResult(result, options, theme, isError) {
140
+ if (options.isPartial) {
141
+ return theme.fg("warning", "Running agent-browser...");
142
+ }
143
+ const outputText = getPrimaryTextContent(result);
144
+ const failureCategoryNotice = formatModelVisibleFailureCategoryNotice(result.details);
145
+ const outputLines = colorizeToolOutputLines(outputText, theme, isError);
146
+ if (failureCategoryNotice && outputLines.length > 0) {
147
+ outputLines.unshift(theme.fg("error", failureCategoryNotice), "");
148
+ }
149
+ if (outputLines.length === 0) {
150
+ const details = isRecord(result.details) ? result.details : undefined;
151
+ const rawSummary = typeof details?.summary === "string" ? details.summary : isError ? "agent-browser failed" : "Done";
152
+ const sanitizedSummary = sanitizeDisplayText(rawSummary).trim();
153
+ const summary = sanitizedSummary.length > 0 ? sanitizedSummary : isError ? "agent-browser failed" : "Done";
154
+ return isError ? theme.fg("error", summary) : theme.fg("success", summary);
155
+ }
156
+ return `\n${outputLines.join("\n")}`;
157
+ }
158
+ function formatModelVisibleFailureCategoryNotice(details) {
159
+ if (!isRecord(details) || details.resultCategory !== "failure")
160
+ return undefined;
161
+ const failureCategory = typeof details.failureCategory === "string" && details.failureCategory.length > 0
162
+ ? details.failureCategory
163
+ : undefined;
164
+ return `Result category: failure${failureCategory ? `; failureCategory: ${failureCategory}` : ""}; Pi tool isError: true.`;
165
+ }
166
+ function agentBrowserToolResultRequestedJson(event) {
167
+ const details = isRecord(event.details) ? event.details : undefined;
168
+ const detailArgs = Array.isArray(details?.args) ? details.args : undefined;
169
+ const inputArgs = isRecord(event.input) && Array.isArray(event.input.args) ? event.input.args : undefined;
170
+ return detailArgs?.includes("--json") === true || inputArgs?.includes("--json") === true;
171
+ }
172
+ function agentBrowserToolResultHasParseableJsonContent(content) {
173
+ return content.some((item) => {
174
+ if (item.type !== "text" || typeof item.text !== "string")
175
+ return false;
176
+ const text = item.text.trim();
177
+ if (text.length === 0)
178
+ return false;
179
+ try {
180
+ JSON.parse(text);
181
+ return true;
182
+ }
183
+ catch {
184
+ return false;
185
+ }
186
+ });
187
+ }
188
+ function appendModelVisibleFailureCategoryNotice(content, notice) {
189
+ const noticeContent = { type: "text", text: notice };
190
+ const textIndex = content.findIndex((item) => item.type === "text" && typeof item.text === "string");
191
+ if (textIndex === -1)
192
+ return [noticeContent, ...content];
193
+ const textItem = content[textIndex];
194
+ if (textItem.type !== "text" || typeof textItem.text !== "string" || textItem.text.includes(notice))
195
+ return undefined;
196
+ return content.map((item, index) => index === textIndex
197
+ ? { ...item, text: `${textItem.text}\n\n${notice}` }
198
+ : item);
199
+ }
200
+ export function buildAgentBrowserToolResultPatch(event) {
201
+ if (event.toolName !== "agent_browser")
202
+ return undefined;
203
+ const preservesParseableJson = agentBrowserToolResultRequestedJson(event) && agentBrowserToolResultHasParseableJsonContent(event.content);
204
+ const notice = preservesParseableJson ? undefined : formatModelVisibleFailureCategoryNotice(event.details);
205
+ const content = notice ? appendModelVisibleFailureCategoryNotice(event.content, notice) : undefined;
206
+ const shouldMarkError = isRecord(event.details) && event.details.resultCategory === "failure" && event.isError !== true;
207
+ if (!shouldMarkError && !content)
208
+ return undefined;
209
+ return {
210
+ ...(content ? { content } : {}),
211
+ ...(shouldMarkError ? { isError: true } : {}),
212
+ };
213
+ }
214
+ export class AgentBrowserResultComponent {
215
+ expanded = false;
216
+ theme;
217
+ text = new Text("", 0, 0);
218
+ setState(value, expanded, theme) {
219
+ this.text.setText(value);
220
+ this.expanded = expanded;
221
+ this.theme = theme;
222
+ }
223
+ render(width) {
224
+ const lines = this.text.render(width);
225
+ if (this.expanded || lines.length <= TUI_COLLAPSED_OUTPUT_MAX_LINES) {
226
+ return lines;
227
+ }
228
+ const theme = this.theme;
229
+ if (!theme) {
230
+ return lines.slice(0, TUI_COLLAPSED_OUTPUT_MAX_LINES);
231
+ }
232
+ const hiddenLineCount = lines.length - TUI_COLLAPSED_OUTPUT_MAX_LINES;
233
+ return [
234
+ ...lines.slice(0, TUI_COLLAPSED_OUTPUT_MAX_LINES),
235
+ formatVisualTruncationNotice(hiddenLineCount, lines.length, theme, width),
236
+ ];
237
+ }
238
+ invalidate() {
239
+ this.text.invalidate();
240
+ }
241
+ }