@pensar/apex 2.6.1 → 2.7.0-canary.1572d9a4

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 (328) hide show
  1. package/build/{agent-ayreaj6z.js → agent-3g1b578v.js} +6 -5
  2. package/build/{agent-yby11zaq.js → agent-p8cezgbb.js} +7 -6
  3. package/build/{agent-runs-g37vkrjr.js → agent-runs-f86emmgg.js} +23 -20
  4. package/build/agent-vaq31je6.js +14 -0
  5. package/build/agent-vvdqga09.js +14 -0
  6. package/build/{apps-xn6km9yn.js → apps-3stwnmen.js} +16 -13
  7. package/build/{auth-d105wc64.js → auth-7md9kwda.js} +16 -13
  8. package/build/blackboxAgent-ct8bejef.js +14 -0
  9. package/build/{blackboxPentest-ps78v3w7.js → blackboxPentest-w2nr4md3.js} +21 -15
  10. package/build/{cli-c05y640n.js → cli-1j28cbhy.js} +1 -1
  11. package/build/{cli-d37a42dc.js → cli-2jz2jz06.js} +206 -90
  12. package/build/{cli-az3xq70v.js → cli-4a8dsz2k.js} +4 -4
  13. package/build/{cli-qgz1q9g5.js → cli-58781vcf.js} +1192 -1473
  14. package/build/{cli-gx71jcke.js → cli-7067zzeb.js} +1 -1
  15. package/build/{cli-3sp6nd8d.js → cli-81smmd5w.js} +5 -5
  16. package/build/{cli-k2nwxta0.js → cli-8b25dhky.js} +2 -2
  17. package/build/{cli-fy6vh2a7.js → cli-8sw5zpqz.js} +1 -1
  18. package/build/{cli-709rvekb.js → cli-cg3ypx5n.js} +14 -7
  19. package/build/{cli-dpsw2fe6.js → cli-e9v6zg6h.js} +40941 -40172
  20. package/build/cli-fjxmphg1.js +36 -0
  21. package/build/{cli-7eea4e2y.js → cli-gzb6qrzh.js} +31 -60
  22. package/build/{cli-65g6rcat.js → cli-khnf5xrf.js} +2 -1
  23. package/build/{cli-1ve18npr.js → cli-mdzt2e8j.js} +4 -2
  24. package/build/{cli-n2en7j5b.js → cli-n8mmw4c4.js} +1 -1
  25. package/build/cli-pndb7mh9.js +1193 -0
  26. package/build/cli-px6ehzqx.js +54 -0
  27. package/build/{cli-xtc2t6me.js → cli-qs4msn6x.js} +111 -47
  28. package/build/{cli-kb21qhvm.js → cli-rvybdhgn.js} +4 -3
  29. package/build/{cli-ae8jqxqr.js → cli-v739h7hb.js} +2 -2
  30. package/build/{cli-ngq9dr8n.js → cli-wm8ech0x.js} +3 -3
  31. package/build/cli.js +170 -51
  32. package/build/{config-zpqkd5cz.js → config-e5v1bkh1.js} +1 -1
  33. package/build/{fastStrike-mcjdvwez.js → fastStrike-efp0rjs3.js} +74 -17
  34. package/build/{fixes-kytx5dmj.js → fixes-926cw1ej.js} +16 -13
  35. package/build/{index-n65z6v7b.js → index-3t41p258.js} +7 -6
  36. package/build/{index-qv4cc65p.js → index-bv09af6g.js} +19 -15
  37. package/build/{index-je6hcsqr.js → index-bv6dtwse.js} +1 -1
  38. package/build/{index-4vqdgb42.js → index-jt52ffgn.js} +1657 -1400
  39. package/build/{index-ns4m4s01.js → index-np405b9e.js} +11 -7
  40. package/build/{index-r9yjkfrv.js → index-qys178kp.js} +5 -4
  41. package/build/{index-wqetp6gq.js → index-tpyzq2wq.js} +42 -11
  42. package/build/{index-fv64eb32.js → index-vrcdyebh.js} +2 -2
  43. package/build/{index-dr3tg1w3.js → index-z1g8vbtm.js} +1 -1
  44. package/build/{issues-eb3q9d3a.js → issues-sncyqh14.js} +16 -13
  45. package/build/{knowledge-fqsvtx0f.js → knowledge-esgvy5ws.js} +16 -13
  46. package/build/lance-sacfgs1z.js +232 -0
  47. package/build/lib/{chunk-9yksqgzr.js → chunk-4aevegnc.js} +77 -45
  48. package/build/lib/{chunk-9tt2021m.js → chunk-4kf4a15q.js} +13 -13
  49. package/build/lib/{chunk-fy3bbbqy.js → chunk-5avnedwm.js} +7 -1
  50. package/build/lib/{chunk-bb0ekhkw.js → chunk-5nz5tk3p.js} +76 -22
  51. package/build/lib/{chunk-4hwzqthr.js → chunk-7s8e5wrd.js} +3 -2
  52. package/build/lib/{chunk-yrnrbjes.js → chunk-85kpxwzs.js} +4 -2
  53. package/build/lib/{chunk-mg03jdmt.js → chunk-9jkzk9nc.js} +1 -1
  54. package/build/lib/{chunk-r4j8ybn9.js → chunk-9wwts6r6.js} +824 -77
  55. package/build/lib/{chunk-nhfax4gb.js → chunk-bxznzxdy.js} +5 -1
  56. package/build/lib/{chunk-r2dkp4tb.js → chunk-cqxm95md.js} +1 -1
  57. package/build/lib/{chunk-w66ce82a.js → chunk-e3agqspc.js} +12 -4
  58. package/build/lib/{chunk-ba41jh41.js → chunk-eh5yw385.js} +1137 -333
  59. package/build/lib/{chunk-1azdancq.js → chunk-ewc9r84m.js} +5 -1
  60. package/build/lib/{chunk-2njv7wz3.js → chunk-hbyxyxdc.js} +4 -0
  61. package/build/lib/{chunk-e8yy2k73.js → chunk-jhhwts6w.js} +28 -2
  62. package/build/lib/{chunk-1jvwqnem.js → chunk-kbxbd1kn.js} +108 -44
  63. package/build/lib/{chunk-7pwa92rn.js → chunk-mph5fvk7.js} +1 -1
  64. package/build/lib/chunk-psc23epq.js +107 -0
  65. package/build/lib/{chunk-acgbyf5h.js → chunk-qxad7qjd.js} +4 -2
  66. package/build/lib/{chunk-3c00n0cy.js → chunk-r0v3vvgm.js} +54 -33
  67. package/build/lib/{chunk-1yct6cra.js → chunk-rt13120a.js} +1 -1
  68. package/build/lib/{chunk-v3dk9j7k.js → chunk-sgya016v.js} +93 -22
  69. package/build/lib/{chunk-1fy8azee.js → chunk-txef92hq.js} +1 -1
  70. package/build/lib/{chunk-2qsq76xq.js → chunk-vcd90qrn.js} +189 -90
  71. package/build/lib/{chunk-7gjdygcx.js → chunk-vwr9w3ab.js} +2 -0
  72. package/build/lib/{chunk-z137x08b.js → chunk-wf6ak0m3.js} +92 -70
  73. package/build/lib/{chunk-xhdpgpkm.js → chunk-xft0ms9j.js} +2 -2
  74. package/build/lib/core/agents/agentRuntime.d.ts +3 -1
  75. package/build/lib/core/agents/defineAgent.d.ts +3 -2
  76. package/build/lib/core/agents/lance.d.ts +153 -0
  77. package/build/lib/core/agents/lanceJudge.d.ts +3 -0
  78. package/build/lib/core/agents/offSecAgent/index.d.ts +3 -1
  79. package/build/lib/core/agents/offSecAgent/index.js +16 -14
  80. package/build/lib/core/agents/offSecAgent/offensiveSecurityAgent.d.ts +4 -0
  81. package/build/lib/core/agents/offSecAgent/prompt.d.ts +3 -1
  82. package/build/lib/core/agents/offSecAgent/subagentSpawner.d.ts +18 -2
  83. package/build/lib/core/agents/offSecAgent/subagentSpawner.js +10 -8
  84. package/build/lib/core/agents/offSecAgent/toolExecutionContext.d.ts +3 -0
  85. package/build/lib/core/agents/offSecAgent/toolLifecycle.d.ts +1 -0
  86. package/build/lib/core/agents/offSecAgent/tools/index.js +10 -6
  87. package/build/lib/core/agents/offSecAgent/tools/listMemories.d.ts +11 -1
  88. package/build/lib/core/agents/offSecAgent/tools/reportError.d.ts +2 -1
  89. package/build/lib/core/agents/offSecAgent/tools/runPentestWorkflow.d.ts +20 -1
  90. package/build/lib/core/agents/offSecAgent/tools/spawnPentestAgent.d.ts +4 -7
  91. package/build/lib/core/agents/offSecAgent/tools/spawnPentestSwarm.d.ts +7 -1
  92. package/build/lib/core/agents/offSecAgent/tools/types.d.ts +6 -3
  93. package/build/lib/core/agents/offSecAgent/tools/whiteboxCandidates.d.ts +2 -2
  94. package/build/lib/core/agents/offSecAgent/types.d.ts +19 -3
  95. package/build/lib/core/agents/specialized/attackSurface/blackboxAgent.js +13 -13
  96. package/build/lib/core/agents/specialized/attackSurface/schemas.js +12 -12
  97. package/build/lib/core/agents/specialized/authenticationAgent/index.js +14 -14
  98. package/build/lib/core/agents/specialized/codeAgent/agent.js +13 -13
  99. package/build/lib/core/agents/specialized/codeAgent/prompts.d.ts +1 -0
  100. package/build/lib/core/agents/specialized/cvssScorer/index.d.ts +2 -1
  101. package/build/lib/core/agents/specialized/findingJudge/agent.js +11 -11
  102. package/build/lib/core/agents/specialized/findingJudge/index.d.ts +2 -1
  103. package/build/lib/core/agents/specialized/findingJudge/index.js +4 -4
  104. package/build/lib/core/agents/specialized/patching/index.js +14 -14
  105. package/build/lib/core/agents/specialized/pentest/agent.d.ts +18 -4
  106. package/build/lib/core/agents/specialized/pentest/agent.js +15 -13
  107. package/build/lib/core/agents/specialized/whiteboxAttackSurface/endpointDocumentationAgent.d.ts +2 -1
  108. package/build/lib/core/agents/specialized/whiteboxAttackSurface/index.js +13 -13
  109. package/build/lib/core/ai/ai.d.ts +29 -70
  110. package/build/lib/core/ai/ai.js +5 -3
  111. package/build/lib/core/ai/index.d.ts +1 -0
  112. package/build/lib/core/ai/index.js +16 -4
  113. package/build/lib/core/ai/models/claude-capabilities.d.ts +3 -2
  114. package/build/lib/core/ai/models/concentrate.d.ts +1 -0
  115. package/build/lib/core/ai/models/index.d.ts +1 -1
  116. package/build/lib/core/ai/providers/concentrate.d.ts +1 -0
  117. package/build/lib/core/ai/reasoning.d.ts +44 -0
  118. package/build/lib/core/ai/utils.d.ts +2 -0
  119. package/build/lib/core/ai/utils.js +5 -3
  120. package/build/lib/core/api/index.d.ts +6 -0
  121. package/build/lib/core/api/index.js +32 -23
  122. package/build/lib/core/api/lance.d.ts +6 -0
  123. package/build/lib/core/api/offesecAgent.d.ts +1 -0
  124. package/build/lib/core/api/reasoning.d.ts +12 -0
  125. package/build/lib/core/api/targetedPentest.d.ts +1 -0
  126. package/build/lib/core/api/targetedPentest.js +14 -14
  127. package/build/lib/core/cli/reasoning.d.ts +4 -0
  128. package/build/lib/core/config/config.d.ts +10 -2
  129. package/build/lib/core/config/customProviders.d.ts +11 -0
  130. package/build/lib/core/config/index.js +1 -1
  131. package/build/lib/core/eventBus.js +1 -1
  132. package/build/lib/core/findings/registry.d.ts +3 -1
  133. package/build/lib/core/findings/registry.js +4 -4
  134. package/build/lib/core/observability/index.js +1 -1
  135. package/build/lib/core/observability/telemetry.d.ts +4 -0
  136. package/build/lib/core/session/index.d.ts +47 -0
  137. package/build/lib/core/session/index.js +6 -4
  138. package/build/lib/core/session/persistence.d.ts +7 -0
  139. package/build/lib/core/session/persistence.js +8 -4
  140. package/build/lib/core/tools/backends/index.js +1 -1
  141. package/build/lib/core/tools/backends/resolve.d.ts +1 -0
  142. package/build/lib/core/workflows/fastStrike.d.ts +3 -1
  143. package/build/lib/core/workflows/pentest.d.ts +12 -2
  144. package/build/lib/core/workflows/pentest.js +19 -19
  145. package/build/lib/core/workflows/seams.js +5 -5
  146. package/build/lib/core/workflows/threatModel.d.ts +1 -0
  147. package/build/lib/core/workflows/whiteboxAttackSurface.d.ts +6 -4
  148. package/build/lib/core/workflows/whiteboxAttackSurface.js +15 -15
  149. package/build/lib/index.js +25 -25
  150. package/build/{logs-x62b7hk1.js → logs-bcbjpjp6.js} +16 -13
  151. package/build/{native-rollout-evidence-c9yhfqcs.js → native-rollout-evidence-rph1774m.js} +5 -5
  152. package/build/offesecAgent-81h1p6ee.js +32 -0
  153. package/build/pentest-2q20q6n1.js +23 -0
  154. package/build/{pentests-e0f32aqx.js → pentests-jgw031mc.js} +16 -13
  155. package/build/recordedRunClient-6axj6fba.js +11 -0
  156. package/build/subagentSpawner-a861gvt0.js +12 -0
  157. package/build/targetedPentest-6yxznt7s.js +91 -0
  158. package/build/{targets-xj9g3q0z.js → targets-bjah19dp.js} +16 -13
  159. package/build/threatModel-739kpexm.js +24 -0
  160. package/build/{uninstall-7s784q4a.js → uninstall-yxrn9edt.js} +1 -1
  161. package/build/{upload-4gvhwmvr.js → upload-34ewrjp5.js} +4 -4
  162. package/build/{utils-cjrz64pc.js → utils-fzm66efw.js} +5 -5
  163. package/package.json +2 -1
  164. package/src/cli/issues.test.ts +17 -1
  165. package/src/cli/lance-verifier.test.ts +57 -0
  166. package/src/cli/lance-verifier.ts +73 -0
  167. package/src/cli/lance.test.ts +71 -0
  168. package/src/cli/lance.ts +48 -0
  169. package/src/cli.ts +109 -19
  170. package/src/core/agents/agentRuntime.test.ts +42 -0
  171. package/src/core/agents/agentRuntime.ts +7 -2
  172. package/src/core/agents/defineAgent.ts +3 -1
  173. package/src/core/agents/lance.test.ts +421 -0
  174. package/src/core/agents/lance.ts +701 -0
  175. package/src/core/agents/lanceJudge.test.ts +166 -0
  176. package/src/core/agents/lanceJudge.ts +115 -0
  177. package/src/core/agents/offSecAgent/index.ts +3 -0
  178. package/src/core/agents/offSecAgent/interruptedStepFinalization.test.ts +51 -0
  179. package/src/core/agents/offSecAgent/lance.test.ts +188 -0
  180. package/src/core/agents/offSecAgent/offensiveSecurityAgent.test.ts +92 -5
  181. package/src/core/agents/offSecAgent/offensiveSecurityAgent.ts +244 -41
  182. package/src/core/agents/offSecAgent/prompt.test.ts +46 -0
  183. package/src/core/agents/offSecAgent/prompt.ts +52 -8
  184. package/src/core/agents/offSecAgent/selectiveConstruction.publicPath.test.ts +38 -0
  185. package/src/core/agents/offSecAgent/selectiveConstruction.test.ts +64 -0
  186. package/src/core/agents/offSecAgent/subagentSpawner.hooks.test.ts +11 -3
  187. package/src/core/agents/offSecAgent/subagentSpawner.reasoning.test.ts +167 -0
  188. package/src/core/agents/offSecAgent/subagentSpawner.ts +82 -28
  189. package/src/core/agents/offSecAgent/toolExecutionContext.test.ts +230 -0
  190. package/src/core/agents/offSecAgent/toolExecutionContext.ts +56 -0
  191. package/src/core/agents/offSecAgent/toolLifecycle.ts +2 -0
  192. package/src/core/agents/offSecAgent/tools/delegateAuth.ts +4 -2
  193. package/src/core/agents/offSecAgent/tools/documentFinding.test.ts +9 -4
  194. package/src/core/agents/offSecAgent/tools/documentFinding.ts +10 -9
  195. package/src/core/agents/offSecAgent/tools/listMemories.test.ts +230 -0
  196. package/src/core/agents/offSecAgent/tools/listMemories.ts +73 -6
  197. package/src/core/agents/offSecAgent/tools/reportError.test.ts +6 -0
  198. package/src/core/agents/offSecAgent/tools/reportError.ts +10 -2
  199. package/src/core/agents/offSecAgent/tools/runAttackSurface.ts +7 -4
  200. package/src/core/agents/offSecAgent/tools/runPentestWorkflow.test.ts +57 -0
  201. package/src/core/agents/offSecAgent/tools/runPentestWorkflow.ts +21 -1
  202. package/src/core/agents/offSecAgent/tools/runWhiteboxScan.ts +5 -2
  203. package/src/core/agents/offSecAgent/tools/spawnCodingAgent.ts +50 -67
  204. package/src/core/agents/offSecAgent/tools/spawnPentestAgent.test.ts +79 -3
  205. package/src/core/agents/offSecAgent/tools/spawnPentestAgent.ts +36 -16
  206. package/src/core/agents/offSecAgent/tools/spawnPentestSwarm.ts +28 -5
  207. package/src/core/agents/offSecAgent/tools/threatModelGenerator.ts +4 -3
  208. package/src/core/agents/offSecAgent/tools/types.ts +12 -2
  209. package/src/core/agents/offSecAgent/tools/updateTask.ts +5 -1
  210. package/src/core/agents/offSecAgent/tools/whiteboxCandidates.ts +11 -4
  211. package/src/core/agents/offSecAgent/types.ts +22 -1
  212. package/src/core/agents/specialized/codeAgent/agent.test.ts +7 -0
  213. package/src/core/agents/specialized/codeAgent/agent.ts +9 -2
  214. package/src/core/agents/specialized/codeAgent/prompts.ts +6 -0
  215. package/src/core/agents/specialized/cvssScorer/index.test.ts +2 -1
  216. package/src/core/agents/specialized/cvssScorer/index.ts +3 -0
  217. package/src/core/agents/specialized/findingJudge/index.ts +6 -0
  218. package/src/core/agents/specialized/pentest/agent.test.ts +155 -0
  219. package/src/core/agents/specialized/pentest/agent.ts +181 -52
  220. package/src/core/agents/specialized/pentest/results.test.ts +59 -4
  221. package/src/core/agents/specialized/whiteboxAttackSurface/endpointDocumentationAgent.concurrency.test.ts +59 -2
  222. package/src/core/agents/specialized/whiteboxAttackSurface/endpointDocumentationAgent.hooks.test.ts +127 -0
  223. package/src/core/agents/specialized/whiteboxAttackSurface/endpointDocumentationAgent.ts +74 -68
  224. package/src/core/ai/ai.durability-hooks.test.ts +25 -7
  225. package/src/core/ai/ai.lance.test.ts +581 -0
  226. package/src/core/ai/ai.operator-context.bench.test.ts +1390 -0
  227. package/src/core/ai/ai.recorded-context.test.ts +89 -8
  228. package/src/core/ai/ai.test.ts +81 -59
  229. package/src/core/ai/ai.ts +453 -327
  230. package/src/core/ai/compactionTelemetry.test.ts +69 -17
  231. package/src/core/ai/index.ts +11 -0
  232. package/src/core/ai/models/anthropic.ts +6 -0
  233. package/src/core/ai/models/bedrock.ts +18 -0
  234. package/src/core/ai/models/claude-capabilities.ts +29 -8
  235. package/src/core/ai/models/concentrate.ts +52 -0
  236. package/src/core/ai/models/index.ts +25 -4
  237. package/src/core/ai/models/models.test.ts +179 -7
  238. package/src/core/ai/models/openrouter-reasoning.json +219 -0
  239. package/src/core/ai/models/openrouter.ts +43 -1
  240. package/src/core/ai/providers/anthropic-models.test.ts +60 -1
  241. package/src/core/ai/providers/bedrock-models.test.ts +81 -0
  242. package/src/core/ai/providers/concentrate.test.ts +31 -0
  243. package/src/core/ai/providers/concentrate.ts +11 -0
  244. package/src/core/ai/providers/custom.test.ts +74 -0
  245. package/src/core/ai/providers/custom.ts +3 -1
  246. package/src/core/ai/providers/gateway-models.test.ts +16 -6
  247. package/src/core/ai/providers/pensarFormatters.ts +8 -1
  248. package/src/core/ai/reasoning.test.ts +313 -0
  249. package/src/core/ai/reasoning.ts +500 -0
  250. package/src/core/ai/streamIdleTimeout.test.ts +21 -0
  251. package/src/core/ai/utils.native-rollout-evidence.test.ts +21 -8
  252. package/src/core/ai/utils.ts +269 -163
  253. package/src/core/api/attackSurface.ts +1 -0
  254. package/src/core/api/blackboxPentest.ts +9 -1
  255. package/src/core/api/index.ts +17 -0
  256. package/src/core/api/lance.ts +23 -0
  257. package/src/core/api/offesecAgent.test.ts +51 -0
  258. package/src/core/api/offesecAgent.ts +15 -1
  259. package/src/core/api/reasoning.test.ts +213 -0
  260. package/src/core/api/reasoning.ts +44 -0
  261. package/src/core/api/recordedRun.loop.test.ts +5 -1
  262. package/src/core/api/targetedPentest.test.ts +14 -2
  263. package/src/core/api/targetedPentest.ts +52 -5
  264. package/src/core/cli/reasoning.test.ts +149 -0
  265. package/src/core/cli/reasoning.ts +95 -0
  266. package/src/core/config/config.test.ts +35 -0
  267. package/src/core/config/config.ts +11 -0
  268. package/src/core/config/customProviders.ts +21 -2
  269. package/src/core/eventBus.ts +1 -0
  270. package/src/core/findings/registry.test.ts +9 -1
  271. package/src/core/findings/registry.ts +6 -0
  272. package/src/core/observability/telemetry.test.ts +131 -79
  273. package/src/core/observability/telemetry.ts +5 -0
  274. package/src/core/runtime/sqliteRunObservation.test.ts +1 -1
  275. package/src/core/session/index.ts +38 -0
  276. package/src/core/session/persistence.test.ts +62 -0
  277. package/src/core/session/persistence.ts +56 -0
  278. package/src/core/tools/backends/resolve.ts +7 -0
  279. package/src/core/tools/backends/whiteboxJobs.test.ts +9 -8
  280. package/src/core/workflows/fastStrike.seams.test.ts +149 -0
  281. package/src/core/workflows/fastStrike.test.ts +18 -1
  282. package/src/core/workflows/fastStrike.ts +106 -11
  283. package/src/core/workflows/pentest.test.ts +104 -0
  284. package/src/core/workflows/pentest.ts +128 -7
  285. package/src/core/workflows/seams.test.ts +13 -0
  286. package/src/core/workflows/seams.ts +5 -1
  287. package/src/core/workflows/threatModel.ts +2 -0
  288. package/src/core/workflows/whiteboxAttackSurface.test.ts +74 -2
  289. package/src/core/workflows/whiteboxAttackSurface.ts +102 -73
  290. package/src/tui/command-registry.test.ts +12 -0
  291. package/src/tui/command-registry.ts +10 -0
  292. package/src/tui/components/chat/config-view.tsx +6 -10
  293. package/src/tui/components/chat/home-view.tsx +2 -2
  294. package/src/tui/components/chat/input-area.tsx +2 -2
  295. package/src/tui/components/chat/loading-indicator.tsx +20 -4
  296. package/src/tui/components/chat/message-list.tsx +1 -0
  297. package/src/tui/components/commands/__tests__/advanced-settings-lifecycle.tsx +164 -0
  298. package/src/tui/components/commands/advanced-settings.test.ts +34 -0
  299. package/src/tui/components/commands/advanced-settings.tsx +220 -31
  300. package/src/tui/components/commands/models-display.tsx +7 -1
  301. package/src/tui/components/model-picker/ModelPicker.tsx +65 -103
  302. package/src/tui/components/model-picker/ModelPickerDialog.tsx +8 -14
  303. package/src/tui/components/model-picker/__tests__/reasoning-control.tsx +162 -0
  304. package/src/tui/components/model-picker/reasoning-control.test.ts +15 -0
  305. package/src/tui/components/operator-dashboard/index.tsx +166 -50
  306. package/src/tui/components/operator-dashboard/logic.test.ts +144 -2
  307. package/src/tui/components/operator-dashboard/logic.ts +54 -3
  308. package/src/tui/components/operator-dashboard/run-events.test.ts +3 -1
  309. package/src/tui/components/shared/__tests__/tool-renderer-lifecycle.tsx +18 -0
  310. package/src/tui/components/shared/action-label.test.ts +9 -0
  311. package/src/tui/components/shared/compacting-icon.tsx +18 -0
  312. package/src/tui/components/shared/index.ts +1 -0
  313. package/src/tui/components/shared/tool-registry.ts +1 -0
  314. package/src/tui/components/shared/tool-renderer.tsx +21 -7
  315. package/src/tui/context/agent.tsx +32 -79
  316. package/src/tui/context/route.tsx +2 -0
  317. package/src/tui/index.tsx +1 -0
  318. package/src/tui/keybindings/registry.ts +2 -0
  319. package/build/agent-6w7egcf1.js +0 -13
  320. package/build/agent-9zx75feh.js +0 -13
  321. package/build/blackboxAgent-s56sgx9b.js +0 -13
  322. package/build/cli-g06s7edq.js +0 -11
  323. package/build/lib/chunk-z96pbjhd.js +0 -56
  324. package/build/offesecAgent-5whnpeta.js +0 -22
  325. package/build/pentest-e61hc38s.js +0 -22
  326. package/build/recordedRunClient-dp032c32.js +0 -11
  327. package/build/targetedPentest-rcbs4nvp.js +0 -57
  328. package/build/threatModel-jkxfa40s.js +0 -21
@@ -0,0 +1,1193 @@
1
+ import {
2
+ createLogger,
3
+ init_structured,
4
+ scopedLogger,
5
+ init_lazyLogger,
6
+ getModelSettings,
7
+ generateObjectResponse,
8
+ init_ai2
9
+ } from "./cli-e9v6zg6h.js";
10
+ import {
11
+ newSessionId,
12
+ init_id,
13
+ runWithNativeRolloutSession
14
+ } from "./cli-se8ae8z3.js";
15
+ import {
16
+ init_zod
17
+ } from "./cli-3qznjsnr.js";
18
+ import {
19
+ string,
20
+ number,
21
+ boolean,
22
+ array,
23
+ object
24
+ } from "./cli-mz5pk30x.js";
25
+ import {
26
+ require_src6
27
+ } from "./cli-bb02pjt0.js";
28
+ import {
29
+ __toESM
30
+ } from "./cli-h6y3bt60.js";
31
+
32
+ // src/core/eventBus.ts
33
+ import { EventEmitter } from "node:events";
34
+ var CHILD_BUS_FORWARD_POLICY = {
35
+ "text-delta": "forward",
36
+ "reasoning-delta": "forward",
37
+ "reasoning-start": "forward",
38
+ "reasoning-end": "forward",
39
+ "tool-call-start": "forward",
40
+ "tool-call-delta": "forward",
41
+ "tool-call-complete": "forward",
42
+ "tool-result": "forward",
43
+ "subagent-spawn": "forward",
44
+ "subagent-complete": "forward",
45
+ "step-finish": "forward",
46
+ "command-output": "forward",
47
+ error: "forward",
48
+ "trace-record": "forward",
49
+ "workflow-phase-start": "parent-only",
50
+ "workflow-phase-complete": "parent-only",
51
+ "app-analysis-progress": "parent-only"
52
+ };
53
+ var CHILD_BUS_FORWARDED_EVENTS = Object.keys(CHILD_BUS_FORWARD_POLICY).filter((key) => CHILD_BUS_FORWARD_POLICY[key] === "forward");
54
+
55
+ class AgentEventBus {
56
+ emitter = new EventEmitter;
57
+ constructor() {
58
+ this.emitter.setMaxListeners(50);
59
+ }
60
+ on(event, handler) {
61
+ this.emitter.on(event, handler);
62
+ return this;
63
+ }
64
+ once(event, handler) {
65
+ this.emitter.once(event, handler);
66
+ return this;
67
+ }
68
+ off(event, handler) {
69
+ this.emitter.off(event, handler);
70
+ return this;
71
+ }
72
+ emit(event, payload) {
73
+ return this.emitter.emit(event, payload);
74
+ }
75
+ removeAllListeners(event) {
76
+ if (event) {
77
+ this.emitter.removeAllListeners(event);
78
+ } else {
79
+ this.emitter.removeAllListeners();
80
+ }
81
+ return this;
82
+ }
83
+ static attachChild(child, parent, childSessionId) {
84
+ if (!parent)
85
+ return;
86
+ for (const key of CHILD_BUS_FORWARDED_EVENTS) {
87
+ const forwardKey = key;
88
+ child.on(forwardKey, (payload) => {
89
+ const p = payload;
90
+ const isLifecycle = forwardKey === "subagent-spawn" || forwardKey === "subagent-complete";
91
+ if (isLifecycle) {
92
+ const next = { ...p };
93
+ if (!p.parentSubagentId)
94
+ next.parentSubagentId = childSessionId;
95
+ if (!p.parentSessionId)
96
+ next.parentSessionId = childSessionId;
97
+ parent.emit(forwardKey, next);
98
+ return;
99
+ }
100
+ const next = { ...p };
101
+ if (!p.subagentId)
102
+ next.subagentId = childSessionId;
103
+ if (!p.sessionId)
104
+ next.sessionId = childSessionId;
105
+ parent.emit(forwardKey, next);
106
+ });
107
+ }
108
+ }
109
+ emitStreamPart(chunk, ids) {
110
+ const ctx = typeof ids === "string" ? { subagentId: ids } : ids ?? {};
111
+ const subagentId = ctx.subagentId;
112
+ const sessionId = ctx.sessionId;
113
+ const messageId = ctx.messageId;
114
+ switch (chunk.type) {
115
+ case "text-delta":
116
+ this.emit("text-delta", {
117
+ text: chunk.text,
118
+ subagentId,
119
+ sessionId,
120
+ messageId,
121
+ partId: ctx.textPartId
122
+ });
123
+ break;
124
+ case "reasoning-start":
125
+ this.emit("reasoning-start", { subagentId, sessionId, messageId });
126
+ break;
127
+ case "reasoning-delta":
128
+ this.emit("reasoning-delta", {
129
+ text: chunk.text,
130
+ subagentId,
131
+ sessionId,
132
+ messageId
133
+ });
134
+ break;
135
+ case "reasoning-end":
136
+ this.emit("reasoning-end", { subagentId, sessionId, messageId });
137
+ break;
138
+ case "tool-input-start":
139
+ this.emit("tool-call-start", {
140
+ toolCallId: chunk.id,
141
+ toolName: chunk.toolName,
142
+ subagentId,
143
+ sessionId,
144
+ messageId,
145
+ partId: ctx.toolPartId?.(chunk.id)
146
+ });
147
+ break;
148
+ case "tool-input-delta":
149
+ this.emit("tool-call-delta", {
150
+ toolCallId: chunk.id,
151
+ argsTextDelta: chunk.delta,
152
+ subagentId,
153
+ sessionId,
154
+ messageId,
155
+ partId: ctx.toolPartId?.(chunk.id)
156
+ });
157
+ break;
158
+ case "tool-call": {
159
+ const tc = chunk;
160
+ this.emit("tool-call-complete", {
161
+ toolCallId: tc.toolCallId,
162
+ toolName: tc.toolName,
163
+ args: tc.args ?? tc.input,
164
+ subagentId,
165
+ sessionId,
166
+ messageId,
167
+ partId: ctx.toolPartId?.(tc.toolCallId)
168
+ });
169
+ break;
170
+ }
171
+ case "tool-result": {
172
+ if (chunk.preliminary)
173
+ break;
174
+ const tr = chunk;
175
+ this.emit("tool-result", {
176
+ toolCallId: tr.toolCallId,
177
+ toolName: tr.toolName,
178
+ result: tr.result ?? tr.output,
179
+ subagentId,
180
+ sessionId,
181
+ messageId,
182
+ partId: ctx.toolPartId?.(tr.toolCallId)
183
+ });
184
+ break;
185
+ }
186
+ case "error":
187
+ this.emit("error", {
188
+ error: chunk.error,
189
+ subagentId
190
+ });
191
+ break;
192
+ }
193
+ }
194
+ }
195
+
196
+ // src/core/agents/offSecAgent/subagentSpawner.ts
197
+ init_ai2();
198
+
199
+ // src/core/utils/concurrency.ts
200
+ var import_api = __toESM(require_src6(), 1);
201
+ async function runWithBoundedConcurrency(items, concurrency, fn, abortSignal) {
202
+ const results = new Array(items.length).fill(null);
203
+ const parentContext = import_api.context.active();
204
+ let nextIdx = 0;
205
+ let completed = 0;
206
+ await new Promise((resolve) => {
207
+ if (items.length === 0) {
208
+ resolve();
209
+ return;
210
+ }
211
+ let active = 0;
212
+ function canLaunchMore() {
213
+ return active < concurrency && nextIdx < items.length && !abortSignal?.aborted;
214
+ }
215
+ function next() {
216
+ if (completed >= nextIdx && !canLaunchMore()) {
217
+ resolve();
218
+ return;
219
+ }
220
+ while (canLaunchMore()) {
221
+ const idx = nextIdx++;
222
+ active++;
223
+ import_api.context.with(parentContext, () => fn(items[idx], idx)).then((r) => {
224
+ results[idx] = r;
225
+ }).catch(() => {
226
+ results[idx] = null;
227
+ }).finally(() => {
228
+ active--;
229
+ completed++;
230
+ next();
231
+ });
232
+ }
233
+ }
234
+ next();
235
+ });
236
+ return results;
237
+ }
238
+
239
+ // src/core/findings/attackSurfaceRegistry.ts
240
+ import { existsSync, readdirSync, readFileSync } from "node:fs";
241
+ import { join } from "node:path";
242
+ function normalizeAssetUrl(url) {
243
+ let u = url.trim().toLowerCase();
244
+ const hashIdx = u.indexOf("#");
245
+ if (hashIdx !== -1)
246
+ u = u.substring(0, hashIdx);
247
+ const qIdx = u.indexOf("?");
248
+ if (qIdx !== -1)
249
+ u = u.substring(0, qIdx);
250
+ u = u.replace(/^https?:\/\//, "");
251
+ u = u.replace(/^www\./, "");
252
+ if (u.length > 1 && u.endsWith("/")) {
253
+ u = u.replace(/\/+$/, "");
254
+ }
255
+ return u;
256
+ }
257
+ function normalizeAssetName(name) {
258
+ return name.trim().toLowerCase().replace(/[^a-z0-9]+/g, "-").replace(/^-|-$/g, "");
259
+ }
260
+ function generateAssetFingerprint(asset) {
261
+ const normalizedName = normalizeAssetName(asset.assetName);
262
+ const assetType = asset.assetType.toLowerCase();
263
+ const url = asset.details?.url;
264
+ const appPrefix = asset.appName ? `${normalizeAssetName(asset.appName)}||` : "";
265
+ return {
266
+ urlKey: url ? `${appPrefix}${normalizeAssetUrl(url)}||${assetType}` : null,
267
+ nameKey: `${appPrefix}${normalizedName}||${assetType}`
268
+ };
269
+ }
270
+
271
+ class AttackSurfaceRegistry {
272
+ urlKeys = new Map;
273
+ nameKeys = new Map;
274
+ assets = [];
275
+ mutex = Promise.resolve();
276
+ get size() {
277
+ return this.assets.length;
278
+ }
279
+ getAssets() {
280
+ return [...this.assets];
281
+ }
282
+ static fromDirectory(assetsPath) {
283
+ const registry = new AttackSurfaceRegistry;
284
+ if (!existsSync(assetsPath))
285
+ return registry;
286
+ const files = readdirSync(assetsPath).filter((f) => f.endsWith(".json"));
287
+ for (const file of files) {
288
+ try {
289
+ const raw = readFileSync(join(assetsPath, file), "utf-8");
290
+ const asset = JSON.parse(raw);
291
+ if (asset && typeof asset.assetName === "string" && typeof asset.assetType === "string") {
292
+ registry.indexAsset(asset);
293
+ }
294
+ } catch {}
295
+ }
296
+ return registry;
297
+ }
298
+ static fromAssets(assets) {
299
+ const registry = new AttackSurfaceRegistry;
300
+ for (const a of assets) {
301
+ registry.indexAsset(a);
302
+ }
303
+ return registry;
304
+ }
305
+ isDuplicate(asset) {
306
+ const { urlKey, nameKey } = generateAssetFingerprint(asset);
307
+ if (urlKey) {
308
+ const urlMatch = this.urlKeys.get(urlKey);
309
+ if (urlMatch) {
310
+ return {
311
+ duplicate: true,
312
+ matchedAsset: urlMatch,
313
+ matchType: "exact-url"
314
+ };
315
+ }
316
+ }
317
+ const nameMatch = this.nameKeys.get(nameKey);
318
+ if (nameMatch) {
319
+ return {
320
+ duplicate: true,
321
+ matchedAsset: nameMatch,
322
+ matchType: "exact-name"
323
+ };
324
+ }
325
+ return { duplicate: false };
326
+ }
327
+ async register(asset) {
328
+ return new Promise((resolve) => {
329
+ this.mutex = this.mutex.then(() => {
330
+ const check = this.isDuplicate(asset);
331
+ if (check.duplicate) {
332
+ resolve(check);
333
+ } else {
334
+ this.indexAsset(asset);
335
+ resolve({ duplicate: false });
336
+ }
337
+ });
338
+ });
339
+ }
340
+ async unregister(asset) {
341
+ return new Promise((resolve) => {
342
+ this.mutex = this.mutex.then(() => {
343
+ this.removeAsset(asset);
344
+ resolve();
345
+ });
346
+ });
347
+ }
348
+ removeAsset(asset) {
349
+ const { urlKey, nameKey } = generateAssetFingerprint(asset);
350
+ if (urlKey && this.urlKeys.get(urlKey) === asset) {
351
+ this.urlKeys.delete(urlKey);
352
+ }
353
+ if (this.nameKeys.get(nameKey) === asset) {
354
+ this.nameKeys.delete(nameKey);
355
+ }
356
+ const idx = this.assets.indexOf(asset);
357
+ if (idx !== -1) {
358
+ this.assets.splice(idx, 1);
359
+ }
360
+ }
361
+ indexAsset(asset) {
362
+ const { urlKey, nameKey } = generateAssetFingerprint(asset);
363
+ if (urlKey && !this.urlKeys.has(urlKey)) {
364
+ this.urlKeys.set(urlKey, asset);
365
+ }
366
+ if (!this.nameKeys.has(nameKey)) {
367
+ this.nameKeys.set(nameKey, asset);
368
+ }
369
+ this.assets.push(asset);
370
+ }
371
+ }
372
+
373
+ // src/core/findings/registry.ts
374
+ init_zod();
375
+ init_ai2();
376
+ init_structured();
377
+ init_lazyLogger();
378
+ import { existsSync as existsSync2, readdirSync as readdirSync2, readFileSync as readFileSync2 } from "node:fs";
379
+ import { join as join2 } from "node:path";
380
+ var log = scopedLogger(() => createLogger("findings:registry"));
381
+ var VULN_CLASS_PATTERNS = [
382
+ [/sql\s*injection/i, "sql-injection"],
383
+ [/command\s*injection/i, "command-injection"],
384
+ [/remote\s*code\s*execution|(\b)rce(\b)/i, "rce"],
385
+ [/server[\s-]*side\s*request\s*forgery|(\b)ssrf(\b)/i, "ssrf"],
386
+ [/cross[\s-]*site\s*request\s*forgery|(\b)csrf(\b)/i, "csrf"],
387
+ [
388
+ /path\s*traversal|directory\s*traversal|local\s*file\s*inclusion|\blfi\b/i,
389
+ "path-traversal"
390
+ ],
391
+ [
392
+ /\bmissing\s*auth|\bno\s*auth|unauthenticated\s+access/i,
393
+ "missing-authentication"
394
+ ],
395
+ [/\bidor\b|insecure\s*direct\s*object/i, "idor"],
396
+ [/\bxss\b|cross[\s-]*site\s*scripting/i, "xss"],
397
+ [/missing\s*content\s*security\s*policy|missing\s*csp\b/i, "missing-csp"],
398
+ [/\bcors\b|cross[\s-]*origin/i, "cors"],
399
+ [/authentication\s*bypass|auth\s*bypass/i, "auth-bypass"],
400
+ [/privilege\s*escalation/i, "privilege-escalation"],
401
+ [
402
+ /information\s*disclosure|sensitive\s*data\s*exposure/i,
403
+ "information-disclosure"
404
+ ],
405
+ [/open\s*redirect/i, "open-redirect"],
406
+ [
407
+ /missing.*rate[\s-]*limit|rate[\s-]*limit.*missing|no\s*rate[\s-]*limit/i,
408
+ "missing-rate-limiting"
409
+ ],
410
+ [
411
+ /user[\s-]*enumeration|account[\s-]*enumeration|email[\s-]*enumeration/i,
412
+ "user-enumeration"
413
+ ],
414
+ [
415
+ /hardcoded[\s-]*credential|hardcoded[\s-]*password|hardcoded[\s-]*key|exposed[\s-]*api[\s-]*key/i,
416
+ "hardcoded-credentials"
417
+ ],
418
+ [/captcha[\s-]*bypass|missing[\s-]*captcha/i, "captcha-bypass"],
419
+ [/missing.*header|security\s*header/i, "missing-security-header"]
420
+ ];
421
+ var URL_PATH_PATTERN = /(?:https?:\/\/[^\s]+|\/[a-z0-9_\-/{}.:]+|\b(?:endpoint|url|path|route)\b)/gi;
422
+ function extractVulnClass(title) {
423
+ const t = title.trim();
424
+ for (const [pattern, cls] of VULN_CLASS_PATTERNS) {
425
+ if (pattern.test(t))
426
+ return cls;
427
+ }
428
+ return t.toLowerCase().replace(/[^a-z0-9]+/g, "-").replace(/^-|-$/g, "").substring(0, 60);
429
+ }
430
+ function classifyFromContent(finding) {
431
+ const titleClass = extractVulnClass(finding.title);
432
+ if (titleClass === "idor") {
433
+ const corpus = `${finding.description ?? ""} ${finding.evidence ?? ""}`;
434
+ const missingAuthPattern = /no\s+authentication|unauthenticated|without\s+authentication|PR:N|PR=N/i;
435
+ if (missingAuthPattern.test(corpus)) {
436
+ return "missing-authentication";
437
+ }
438
+ }
439
+ return titleClass;
440
+ }
441
+ function extractTitleStem(title) {
442
+ return title.replace(URL_PATH_PATTERN, "").replace(/[^a-zA-Z0-9 ]/g, " ").replace(/\s+/g, " ").trim().toLowerCase();
443
+ }
444
+ function normalizeEndpoint(endpoint) {
445
+ let e = endpoint.trim().toLowerCase();
446
+ const hashIdx = e.indexOf("#");
447
+ if (hashIdx !== -1)
448
+ e = e.substring(0, hashIdx);
449
+ const qIdx = e.indexOf("?");
450
+ if (qIdx !== -1)
451
+ e = e.substring(0, qIdx);
452
+ if (e.length > 1 && e.endsWith("/")) {
453
+ e = e.replace(/\/+$/, "");
454
+ }
455
+ return e;
456
+ }
457
+ function generateFingerprint(finding) {
458
+ const vulnClass = classifyFromContent(finding);
459
+ const stem = extractTitleStem(finding.title);
460
+ const endpoint = normalizeEndpoint(finding.endpoint);
461
+ return {
462
+ exactKey: `${endpoint}||${vulnClass}`,
463
+ appWideKey: stem
464
+ };
465
+ }
466
+ var SemanticDedupResultSchema = object({
467
+ isDuplicate: boolean().describe("Whether the new finding is a duplicate of an existing one"),
468
+ matchedIndex: number().optional().describe("1-based index of the matched existing finding, if duplicate"),
469
+ reasoning: string().describe("Brief explanation of why this is or is not a duplicate")
470
+ });
471
+ var SEMANTIC_DEDUP_SYSTEM = `You are a security finding deduplication specialist. Your task is to determine whether a new vulnerability finding is a duplicate of any existing findings.
472
+
473
+ Two findings are duplicates if they describe the SAME underlying vulnerability, even if:
474
+ - They use different phrasing or terminology
475
+ - They affect different endpoints but share the same root cause
476
+ - One is more specific/detailed than the other
477
+
478
+ Two findings are NOT duplicates if they describe genuinely different vulnerabilities, even if:
479
+ - They affect the same endpoint
480
+ - They are the same class of vulnerability but with different root causes (e.g., reflected XSS vs stored XSS)
481
+
482
+ Be conservative: when in doubt, mark as NOT a duplicate. It is better to allow a borderline finding through than to suppress a genuinely new one.`;
483
+ var MAX_SEMANTIC_DEDUP_FINDINGS = 25;
484
+ function buildSemanticDedupPrompt(newFinding, existingFindings) {
485
+ const capped = existingFindings.slice(-MAX_SEMANTIC_DEDUP_FINDINGS);
486
+ const offset = existingFindings.length - capped.length;
487
+ const existingList = capped.map((f, i) => `${offset + i + 1}. [${f.severity}] "${f.title}" — endpoint: ${f.endpoint}
488
+ Description: ${f.description.substring(0, 200)}`).join(`
489
+
490
+ `);
491
+ return `## New Finding
492
+ Title: "${newFinding.title}"
493
+ Endpoint: ${newFinding.endpoint}
494
+ Severity: ${newFinding.severity}
495
+ Description: ${newFinding.description.substring(0, 300)}
496
+
497
+ ## Existing Findings (${existingFindings.length} total${offset > 0 ? `, showing last ${capped.length}` : ""})
498
+ ${existingList}
499
+
500
+ Is the new finding a duplicate of any existing finding?`;
501
+ }
502
+ var SEVERITY_RANK = {
503
+ CRITICAL: 4,
504
+ HIGH: 3,
505
+ MEDIUM: 2,
506
+ LOW: 1
507
+ };
508
+ function maxSeverity(severities) {
509
+ return severities.reduce((acc, s) => SEVERITY_RANK[s] > SEVERITY_RANK[acc] ? s : acc, "LOW");
510
+ }
511
+ var RootCauseGroupResultSchema = object({
512
+ groups: array(object({
513
+ groupId: string().describe("Short kebab-case identifier for the group"),
514
+ findingIndices: array(number()).describe("0-based indices of findings that share this root cause"),
515
+ rootCause: string().describe("Brief description of the shared underlying misconfiguration or weakness")
516
+ }))
517
+ });
518
+ var ROOT_CAUSE_GROUPING_SYSTEM = `You are a security finding analyst. Your task is to identify findings that share a common root cause.
519
+
520
+ These are NOT duplicates — they are distinct findings that stem from the same underlying misconfiguration, weakness, or architectural issue. Examples:
521
+ - "Email Enumeration via Forgot Password" and "Username Enumeration via Cognito Lockout Response" both stem from Cognito leaking user-existence information
522
+ - "Missing Rate Limiting on Email API" and "Unauthenticated Email Sending via SES API" on the same endpoint — the unauthenticated access is the root cause that enables both
523
+ - Multiple IDOR findings on different endpoints that all stem from missing authorization middleware
524
+
525
+ Group findings when:
526
+ 1. One finding enables or is prerequisite to another
527
+ 2. Both stem from the same underlying misconfiguration (e.g. same missing middleware, same leaky service)
528
+ 3. Fixing the root cause would resolve or mitigate all findings in the group
529
+
530
+ Do NOT group findings that merely share a vulnerability class (e.g. two unrelated XSS on different endpoints with different root causes).
531
+
532
+ Return an empty groups array if no findings share a root cause.`;
533
+ function buildRootCauseGroupingPrompt(findings) {
534
+ const list = findings.map((f, i) => `${i}. [${f.severity}] "${f.title}" — endpoint: ${f.endpoint}
535
+ Description: ${f.description.substring(0, 200)}`).join(`
536
+
537
+ `);
538
+ return `## Findings (${findings.length} total)
539
+ ${list}
540
+
541
+ Which findings share a common root cause? Return groups using 0-based indices.`;
542
+ }
543
+
544
+ class FindingsRegistry {
545
+ exactKeys = new Map;
546
+ appWideKeys = new Map;
547
+ findings = [];
548
+ model;
549
+ reasoning;
550
+ authConfig;
551
+ abortSignal;
552
+ sessionId;
553
+ languageModelMiddleware;
554
+ usageRecorder;
555
+ mutex = Promise.resolve();
556
+ constructor(opts) {
557
+ this.model = opts?.model;
558
+ this.reasoning = opts?.reasoning;
559
+ this.authConfig = opts?.authConfig;
560
+ this.abortSignal = opts?.abortSignal;
561
+ this.sessionId = opts?.sessionId;
562
+ this.languageModelMiddleware = opts?.languageModelMiddleware;
563
+ this.usageRecorder = opts?.usageRecorder;
564
+ }
565
+ get size() {
566
+ return this.findings.length;
567
+ }
568
+ getFindings() {
569
+ return [...this.findings];
570
+ }
571
+ static fromDirectory(findingsPath, opts) {
572
+ const registry = new FindingsRegistry(opts);
573
+ if (!existsSync2(findingsPath))
574
+ return registry;
575
+ const files = readdirSync2(findingsPath).filter((f) => f.endsWith(".json"));
576
+ log.debug(`fromDirectory: path=${findingsPath}, jsonFiles=${files.length}`);
577
+ for (const file of files) {
578
+ try {
579
+ const raw = readFileSync2(join2(findingsPath, file), "utf-8");
580
+ const finding = JSON.parse(raw);
581
+ if (finding && typeof finding.title === "string" && typeof finding.endpoint === "string") {
582
+ registry.indexFinding(finding);
583
+ log.debug(`fromDirectory: indexed "${finding.title}" endpoint="${finding.endpoint}" (file=${file})`);
584
+ } else {
585
+ log.debug(`fromDirectory: skipped (missing title/endpoint) file=${file}`);
586
+ }
587
+ } catch {
588
+ log.debug(`fromDirectory: skipped (malformed) file=${file}`);
589
+ }
590
+ }
591
+ log.debug(`fromDirectory: registry initialized with ${registry.size} findings indexed`);
592
+ return registry;
593
+ }
594
+ static fromFindings(findings, opts) {
595
+ const registry = new FindingsRegistry(opts);
596
+ for (const f of findings) {
597
+ registry.indexFinding(f);
598
+ }
599
+ return registry;
600
+ }
601
+ isDuplicate(finding) {
602
+ const { exactKey, appWideKey } = generateFingerprint(finding);
603
+ const exactMatch = this.exactKeys.get(exactKey);
604
+ if (exactMatch) {
605
+ return {
606
+ duplicate: true,
607
+ matchedFinding: exactMatch,
608
+ matchType: "exact"
609
+ };
610
+ }
611
+ const appWideMatch = this.appWideKeys.get(appWideKey);
612
+ if (appWideMatch) {
613
+ return {
614
+ duplicate: true,
615
+ matchedFinding: appWideMatch,
616
+ matchType: "application-wide"
617
+ };
618
+ }
619
+ return { duplicate: false };
620
+ }
621
+ async register(finding) {
622
+ log.debug(`register: checking "${finding.title}" endpoint="${finding.endpoint}"`);
623
+ const fastResult = await new Promise((resolve) => {
624
+ this.mutex = this.mutex.then(() => {
625
+ const check = this.isDuplicate(finding);
626
+ if (check.duplicate) {
627
+ log.debug(`register: DUPLICATE (${check.matchType}) "${finding.title}" matched="${check.matchedFinding?.title}"`);
628
+ resolve(check);
629
+ } else if (!this.model || this.findings.length === 0) {
630
+ this.indexFinding(finding);
631
+ log.debug(`register: UNIQUE (Tier 1+2, no LLM needed) "${finding.title}" — registry size=${this.size}`);
632
+ resolve({ duplicate: false });
633
+ } else {
634
+ log.debug(`register: Tier 1+2 pass — proceeding to Tier 3 LLM check for "${finding.title}"`);
635
+ resolve(null);
636
+ }
637
+ });
638
+ });
639
+ if (fastResult !== null)
640
+ return fastResult;
641
+ const snapshot = this.getFindings();
642
+ let semanticResult = { duplicate: false };
643
+ try {
644
+ semanticResult = await this.semanticDedup(finding, snapshot);
645
+ } catch {
646
+ log.warn(`register: Tier 3 LLM error for "${finding.title}" — falling back to Tier 1+2 only`);
647
+ }
648
+ if (semanticResult.duplicate) {
649
+ log.debug(`register: DUPLICATE (semantic/Tier 3) "${finding.title}" matched="${semanticResult.matchedFinding?.title}"`);
650
+ return semanticResult;
651
+ }
652
+ return new Promise((resolve) => {
653
+ this.mutex = this.mutex.then(() => {
654
+ const recheck = this.isDuplicate(finding);
655
+ if (recheck.duplicate) {
656
+ log.debug(`register: DUPLICATE (race re-check, ${recheck.matchType}) "${finding.title}" matched="${recheck.matchedFinding?.title}"`);
657
+ resolve(recheck);
658
+ } else {
659
+ this.indexFinding(finding);
660
+ log.debug(`register: UNIQUE (all tiers passed) "${finding.title}" — registry size=${this.size}`);
661
+ resolve({ duplicate: false });
662
+ }
663
+ });
664
+ });
665
+ }
666
+ async semanticDedup(finding, existingFindings) {
667
+ if (!this.model || existingFindings.length === 0) {
668
+ return { duplicate: false };
669
+ }
670
+ const prompt = buildSemanticDedupPrompt(finding, existingFindings);
671
+ const result = await generateObjectResponse({
672
+ model: this.model,
673
+ reasoning: this.reasoning,
674
+ schema: SemanticDedupResultSchema,
675
+ prompt,
676
+ system: SEMANTIC_DEDUP_SYSTEM,
677
+ authConfig: this.authConfig,
678
+ abortSignal: this.abortSignal,
679
+ sessionId: this.sessionId,
680
+ languageModelMiddleware: this.languageModelMiddleware,
681
+ usageRecorder: this.usageRecorder,
682
+ operation: "apex.finding.deduplicate"
683
+ });
684
+ if (result.isDuplicate && result.matchedIndex != null) {
685
+ const idx = result.matchedIndex - 1;
686
+ const matched = existingFindings[idx];
687
+ if (matched) {
688
+ return {
689
+ duplicate: true,
690
+ matchedFinding: matched,
691
+ matchType: "semantic"
692
+ };
693
+ }
694
+ }
695
+ return { duplicate: false };
696
+ }
697
+ async unregister(finding) {
698
+ return new Promise((resolve) => {
699
+ this.mutex = this.mutex.then(() => {
700
+ this.removeFinding(finding);
701
+ resolve();
702
+ });
703
+ });
704
+ }
705
+ async groupByRootCause() {
706
+ if (!this.model || this.findings.length < 2) {
707
+ return [];
708
+ }
709
+ const snapshot = [...this.findings];
710
+ const prompt = buildRootCauseGroupingPrompt(snapshot);
711
+ let result;
712
+ try {
713
+ result = await generateObjectResponse({
714
+ model: this.model,
715
+ reasoning: this.reasoning,
716
+ schema: RootCauseGroupResultSchema,
717
+ prompt,
718
+ system: ROOT_CAUSE_GROUPING_SYSTEM,
719
+ authConfig: this.authConfig,
720
+ abortSignal: this.abortSignal,
721
+ sessionId: this.sessionId,
722
+ languageModelMiddleware: this.languageModelMiddleware,
723
+ usageRecorder: this.usageRecorder,
724
+ operation: "apex.finding.root-cause"
725
+ });
726
+ } catch {
727
+ log.warn("groupByRootCause: LLM error — skipping root-cause grouping");
728
+ return [];
729
+ }
730
+ const sanitised = [];
731
+ await new Promise((resolve) => {
732
+ this.mutex = this.mutex.then(() => {
733
+ const baseSeverities = snapshot.map((f) => f.severity);
734
+ for (const group of result.groups) {
735
+ const validIndices = group.findingIndices.filter((i) => i >= 0 && i < snapshot.length);
736
+ if (validIndices.length < 2)
737
+ continue;
738
+ const normalizedSeverity = maxSeverity(validIndices.map((i) => baseSeverities[i]));
739
+ const leadFindingIndex = validIndices.reduce((best, i) => {
740
+ const aRank = SEVERITY_RANK[baseSeverities[i]];
741
+ const bRank = SEVERITY_RANK[baseSeverities[best]];
742
+ if (aRank !== bRank) {
743
+ return aRank > bRank ? i : best;
744
+ }
745
+ return (snapshot[i].description?.length ?? 0) > (snapshot[best].description?.length ?? 0) ? i : best;
746
+ }, validIndices[0]);
747
+ sanitised.push({
748
+ groupId: group.groupId,
749
+ findingIndices: validIndices,
750
+ rootCause: group.rootCause,
751
+ normalizedSeverity,
752
+ leadFindingIndex
753
+ });
754
+ for (const idx of validIndices) {
755
+ const finding = snapshot[idx];
756
+ finding.rootCauseGroup = group.groupId;
757
+ finding.severity = normalizedSeverity;
758
+ finding.rootCauseLead = idx === leadFindingIndex;
759
+ finding.relatedFindings = validIndices.filter((i) => i !== idx).map((i) => snapshot[i]?.title);
760
+ }
761
+ }
762
+ resolve();
763
+ });
764
+ });
765
+ return sanitised;
766
+ }
767
+ removeFinding(finding) {
768
+ const { exactKey, appWideKey } = generateFingerprint(finding);
769
+ if (this.exactKeys.get(exactKey) === finding) {
770
+ this.exactKeys.delete(exactKey);
771
+ }
772
+ if (this.appWideKeys.get(appWideKey) === finding) {
773
+ this.appWideKeys.delete(appWideKey);
774
+ }
775
+ const idx = this.findings.indexOf(finding);
776
+ if (idx !== -1) {
777
+ this.findings.splice(idx, 1);
778
+ }
779
+ }
780
+ indexFinding(finding) {
781
+ const { exactKey, appWideKey } = generateFingerprint(finding);
782
+ if (!this.exactKeys.has(exactKey)) {
783
+ this.exactKeys.set(exactKey, finding);
784
+ }
785
+ if (!this.appWideKeys.has(appWideKey)) {
786
+ this.appWideKeys.set(appWideKey, finding);
787
+ }
788
+ this.findings.push(finding);
789
+ }
790
+ }
791
+
792
+ // src/core/workflows/seams.ts
793
+ init_id();
794
+ function inProcessSpawnMany(items, worker, opts) {
795
+ return runWithBoundedConcurrency(items, opts.concurrency, worker, opts.abortSignal);
796
+ }
797
+ var inProcessConcurrencyRunner = {
798
+ spawnMany: inProcessSpawnMany
799
+ };
800
+ var inMemoryRegistryProvider = {
801
+ findings: () => new FindingsRegistry,
802
+ attackSurface: () => new AttackSurfaceRegistry
803
+ };
804
+ var randomSessionIdFactory = {
805
+ newSessionId: () => newSessionId()
806
+ };
807
+ var noBrowserSessionProvider = {
808
+ forChild: () => {
809
+ return;
810
+ }
811
+ };
812
+ var noopOrchestrationHooks = {};
813
+ function withFindingPersistedHook(registry, onFindingPersisted) {
814
+ if (!onFindingPersisted)
815
+ return registry;
816
+ return {
817
+ get size() {
818
+ return registry.size;
819
+ },
820
+ getFindings: () => registry.getFindings(),
821
+ isDuplicate: (finding) => registry.isDuplicate(finding),
822
+ groupByRootCause: () => registry.groupByRootCause(),
823
+ unregister: (finding) => registry.unregister(finding),
824
+ async register(finding) {
825
+ const result = await registry.register(finding);
826
+ if (!result.duplicate)
827
+ await onFindingPersisted(finding);
828
+ return result;
829
+ }
830
+ };
831
+ }
832
+ var DEFAULT_MAX_DEPTH = 3;
833
+ var DEFAULT_MAX_CONCURRENT_CHILDREN = 10;
834
+ var defaultLimits = {
835
+ maxDepth: DEFAULT_MAX_DEPTH,
836
+ maxConcurrentChildren: DEFAULT_MAX_CONCURRENT_CHILDREN
837
+ };
838
+
839
+ class WorkflowLimitExceededError extends Error {
840
+ constructor(message) {
841
+ super(message);
842
+ this.name = "WorkflowLimitExceededError";
843
+ }
844
+ }
845
+ function assertDepth(depth, limits) {
846
+ if (depth > limits.maxDepth) {
847
+ throw new WorkflowLimitExceededError(`workflow depth ${depth} exceeds maxDepth ${limits.maxDepth}`);
848
+ }
849
+ }
850
+ function withConcurrencyLimit(runner, limits) {
851
+ return {
852
+ async spawnMany(items, worker, opts) {
853
+ if (opts.concurrency > limits.maxConcurrentChildren) {
854
+ throw new WorkflowLimitExceededError(`concurrency ${opts.concurrency} exceeds maxConcurrentChildren ${limits.maxConcurrentChildren}`);
855
+ }
856
+ return runner.spawnMany(items, worker, opts);
857
+ }
858
+ };
859
+ }
860
+ function inProcessSeams(overrides) {
861
+ const limits = overrides?.limits ? { ...defaultLimits, ...overrides.limits } : defaultLimits;
862
+ return {
863
+ fanOut: withConcurrencyLimit(overrides?.fanOut ?? inProcessConcurrencyRunner, limits),
864
+ registries: overrides?.registries ?? inMemoryRegistryProvider,
865
+ ids: overrides?.ids ?? randomSessionIdFactory,
866
+ browser: overrides?.browser ?? noBrowserSessionProvider,
867
+ hooks: overrides?.hooks ?? noopOrchestrationHooks,
868
+ limits,
869
+ hooksForItem: overrides?.hooksForItem
870
+ };
871
+ }
872
+ function resolveItemHooks(hooks, seams, item, index) {
873
+ const itemHooks = seams.hooksForItem?.(item, index);
874
+ return {
875
+ ...hooks,
876
+ contextRecorder: undefined,
877
+ inferenceRecorder: undefined,
878
+ toolExecutionRecorder: undefined,
879
+ ...itemHooks,
880
+ ...hooks?.findingPolicy === "external" ? { findingPolicy: "external" } : {}
881
+ };
882
+ }
883
+
884
+ // src/core/agents/offSecAgent/subagentSpawner.ts
885
+ async function spawnBatch2(spawner, requests, opts, limiter) {
886
+ if (spawner.spawnBatch) {
887
+ if (limiter && !spawner.supportsBatchLimiter) {
888
+ throw new Error("Batch spawner must support the shared child limiter before scheduling limited batches");
889
+ }
890
+ return spawner.spawnBatch(requests, { ...opts, limiter });
891
+ }
892
+ const results = await spawner.spawnMany(requests, async (request) => {
893
+ try {
894
+ const run = () => spawner.spawn(request);
895
+ return {
896
+ status: "fulfilled",
897
+ value: await (limiter ? limiter(run) : run())
898
+ };
899
+ } catch (reason) {
900
+ return { status: "rejected", reason };
901
+ }
902
+ }, opts);
903
+ return results.map((result) => {
904
+ if (result === null) {
905
+ opts.abortSignal?.throwIfAborted();
906
+ throw new Error("Subagent batch lost a result");
907
+ }
908
+ return result;
909
+ });
910
+ }
911
+ async function runSpawnedPentestWorker(spec, input) {
912
+ const { TargetedPentestAgent } = await import("./agent-p8cezgbb.js");
913
+ const hooks = resolveItemHooks(input.hooks, input.seams, spec, 0);
914
+ const agent = new TargetedPentestAgent({
915
+ target: spec.target,
916
+ grpc: spec.grpc,
917
+ systemScope: spec.systemScope,
918
+ objectives: spec.objectives,
919
+ context: spec.context,
920
+ role: spec.role,
921
+ findingsRegistry: input.findingsRegistry,
922
+ browserSession: input.browserSession,
923
+ ...getModelSettings(input),
924
+ session: input.session,
925
+ onStepFinish: input.onStepFinish,
926
+ onCacheMetrics: input.onCacheMetrics,
927
+ eventBus: input.eventBus,
928
+ subagentId: input.subagentId,
929
+ subagentName: input.subagentName,
930
+ environmentVariables: input.environmentVariables,
931
+ secretValues: input.secretValues,
932
+ display: input.display,
933
+ ...hooks,
934
+ abortSignal: input.abortSignal && hooks.abortSignal ? AbortSignal.any([input.abortSignal, hooks.abortSignal]) : input.abortSignal ?? hooks.abortSignal
935
+ });
936
+ input.onAgentConstructed?.(agent);
937
+ return agent.consume();
938
+ }
939
+ var runPentestChild = async (spec, ctx) => {
940
+ let constructed;
941
+ const workerSpec = {
942
+ target: spec.target,
943
+ grpc: spec.grpc,
944
+ systemScope: spec.systemScope,
945
+ objectives: spec.objectives,
946
+ context: spec.context,
947
+ role: spec.role
948
+ };
949
+ const workerInput = {
950
+ ...getModelSettings(ctx),
951
+ session: ctx.session,
952
+ abortSignal: ctx.abortSignal,
953
+ onStepFinish: ctx.onStepFinish,
954
+ onCacheMetrics: ctx.onCacheMetrics,
955
+ eventBus: ctx.eventBus,
956
+ subagentId: ctx.subagentId,
957
+ subagentName: ctx.subagentName,
958
+ findingsRegistry: spec.findingsRegistry,
959
+ browserSession: spec.browserSession,
960
+ environmentVariables: ctx.environmentVariables,
961
+ secretValues: ctx.secretValues,
962
+ display: ctx.display,
963
+ hooks: {
964
+ findingPolicy: ctx.findingPolicy,
965
+ backends: ctx.backends,
966
+ sandbox: ctx.sandbox,
967
+ languageModelMiddleware: ctx.languageModelMiddleware,
968
+ usageRecorder: ctx.usageRecorder,
969
+ toolExecutionContext: ctx.toolExecutionContext,
970
+ streamIdFactory: ctx.streamIdFactory
971
+ },
972
+ seams: inProcessSeams(),
973
+ onAgentConstructed: (agent) => {
974
+ constructed = agent;
975
+ }
976
+ };
977
+ return {
978
+ run: () => runSpawnedPentestWorker(workerSpec, workerInput),
979
+ drained: () => constructed?.drained ?? Promise.resolve()
980
+ };
981
+ };
982
+ var runCodeChild = async (spec, ctx) => {
983
+ const { CodeAgent } = await import("./agent-vvdqga09.js");
984
+ const agent = new CodeAgent({
985
+ findingPolicy: ctx.findingPolicy,
986
+ codebasePath: spec.codebasePath,
987
+ objective: spec.objective,
988
+ system: spec.system,
989
+ responseSchema: spec.responseSchema,
990
+ stopWhen: spec.stopWhen,
991
+ excludeTools: spec.excludeTools,
992
+ projectThreatModel: spec.projectThreatModel,
993
+ attackSurfaceRegistry: spec.attackSurfaceRegistry,
994
+ ...getModelSettings(ctx),
995
+ session: ctx.session,
996
+ abortSignal: ctx.abortSignal,
997
+ eventBus: ctx.eventBus,
998
+ subagentId: ctx.subagentId,
999
+ subagentName: ctx.subagentName,
1000
+ sandbox: ctx.sandbox,
1001
+ backends: ctx.backends,
1002
+ display: ctx.display,
1003
+ onStepFinish: ctx.onStepFinish,
1004
+ onCacheMetrics: ctx.onCacheMetrics,
1005
+ languageModelMiddleware: ctx.languageModelMiddleware,
1006
+ usageRecorder: ctx.usageRecorder,
1007
+ toolExecutionContext: ctx.toolExecutionContext,
1008
+ streamIdFactory: ctx.streamIdFactory
1009
+ });
1010
+ return { run: () => agent.consume(), drained: () => agent.drained };
1011
+ };
1012
+ var runWhiteboxChild = async (spec, ctx) => {
1013
+ const { WhiteboxAttackSurfaceAgent } = await import("./index-3t41p258.js");
1014
+ const agent = new WhiteboxAttackSurfaceAgent({
1015
+ findingPolicy: ctx.findingPolicy,
1016
+ codebasePath: spec.codebasePath,
1017
+ attackSurfaceRegistry: spec.attackSurfaceRegistry,
1018
+ ...getModelSettings(ctx),
1019
+ session: ctx.session,
1020
+ abortSignal: ctx.abortSignal,
1021
+ eventBus: ctx.eventBus,
1022
+ subagentId: ctx.subagentId,
1023
+ subagentName: ctx.subagentName,
1024
+ sandbox: ctx.sandbox,
1025
+ backends: ctx.backends,
1026
+ languageModelMiddleware: ctx.languageModelMiddleware,
1027
+ usageRecorder: ctx.usageRecorder,
1028
+ toolExecutionContext: ctx.toolExecutionContext,
1029
+ streamIdFactory: ctx.streamIdFactory
1030
+ });
1031
+ return { run: () => agent.consume(), drained: () => agent.drained };
1032
+ };
1033
+ var runBlackboxChild = async (spec, ctx) => {
1034
+ const { BlackboxAttackSurfaceAgent } = await import("./blackboxAgent-ct8bejef.js");
1035
+ const agent = new BlackboxAttackSurfaceAgent({
1036
+ findingPolicy: ctx.findingPolicy,
1037
+ target: spec.target,
1038
+ attackSurfaceRegistry: spec.attackSurfaceRegistry,
1039
+ ...getModelSettings(ctx),
1040
+ session: ctx.session,
1041
+ abortSignal: ctx.abortSignal,
1042
+ eventBus: ctx.eventBus,
1043
+ subagentId: ctx.subagentId,
1044
+ sandbox: ctx.sandbox,
1045
+ backends: ctx.backends,
1046
+ languageModelMiddleware: ctx.languageModelMiddleware,
1047
+ usageRecorder: ctx.usageRecorder,
1048
+ toolExecutionContext: ctx.toolExecutionContext,
1049
+ streamIdFactory: ctx.streamIdFactory
1050
+ });
1051
+ return { run: () => agent.consume(), drained: () => agent.drained };
1052
+ };
1053
+ var runAuthChild = async (spec, ctx) => {
1054
+ const { runAuthenticationAgent } = await import("./agent-vaq31je6.js");
1055
+ return {
1056
+ run: () => runAuthenticationAgent({
1057
+ findingPolicy: ctx.findingPolicy,
1058
+ target: spec.target,
1059
+ authHints: spec.authHints,
1060
+ session: ctx.session,
1061
+ ...getModelSettings(ctx),
1062
+ abortSignal: ctx.abortSignal,
1063
+ eventBus: ctx.eventBus,
1064
+ subagentId: ctx.subagentId,
1065
+ subagentName: ctx.subagentName,
1066
+ environmentVariables: ctx.environmentVariables,
1067
+ secretValues: ctx.secretValues,
1068
+ backends: ctx.backends,
1069
+ languageModelMiddleware: ctx.languageModelMiddleware,
1070
+ usageRecorder: ctx.usageRecorder,
1071
+ toolExecutionContext: ctx.toolExecutionContext,
1072
+ streamIdFactory: ctx.streamIdFactory
1073
+ })
1074
+ };
1075
+ };
1076
+ var runJudgeChild = async (spec, ctx) => {
1077
+ const { judgeFinding } = await import("./index-np405b9e.js");
1078
+ return {
1079
+ run: () => judgeFinding(spec.judgeInput, {
1080
+ waitForDrain: spec.waitForDrain,
1081
+ ...getModelSettings(ctx),
1082
+ session: ctx.session,
1083
+ abortSignal: ctx.abortSignal,
1084
+ eventBus: ctx.eventBus,
1085
+ subagentId: ctx.subagentId,
1086
+ subagentName: ctx.subagentName,
1087
+ sandbox: ctx.sandbox,
1088
+ backends: ctx.backends,
1089
+ target: spec.target,
1090
+ languageModelMiddleware: ctx.languageModelMiddleware,
1091
+ usageRecorder: ctx.usageRecorder,
1092
+ toolExecutionContext: ctx.toolExecutionContext,
1093
+ streamIdFactory: ctx.streamIdFactory
1094
+ })
1095
+ };
1096
+ };
1097
+ var RUNNERS = {
1098
+ pentest: runPentestChild,
1099
+ code: runCodeChild,
1100
+ "whitebox-attack-surface": runWhiteboxChild,
1101
+ "blackbox-attack-surface": runBlackboxChild,
1102
+ authentication: runAuthChild,
1103
+ "finding-judge": runJudgeChild
1104
+ };
1105
+ function drainBounded(drained, graceMs) {
1106
+ return Promise.race([
1107
+ drained?.catch(() => {}) ?? Promise.resolve(),
1108
+ new Promise((resolve) => {
1109
+ setTimeout(resolve, graceMs).unref?.();
1110
+ })
1111
+ ]);
1112
+ }
1113
+
1114
+ class InProcessSubagentSpawner {
1115
+ ids;
1116
+ browser;
1117
+ ordinal = 0;
1118
+ constructor(ids = randomSessionIdFactory, browser) {
1119
+ this.ids = ids;
1120
+ this.browser = browser;
1121
+ }
1122
+ mintChildId(name) {
1123
+ return this.ids.newSessionId(name ?? "subagent", this.ordinal++);
1124
+ }
1125
+ async spawn(opts) {
1126
+ const childId = opts.subagentId ?? this.mintChildId(opts.subagentName);
1127
+ opts.onSpawned?.(childId);
1128
+ const parentSessionId = opts.parentSessionId ?? opts.parentSubagentId ?? opts.runtime.session.id;
1129
+ const lifecycleBase = {
1130
+ subagentId: childId,
1131
+ ...opts.stampChildSessionId ? { sessionId: childId } : {},
1132
+ ...opts.parentSubagentId !== undefined ? { parentSubagentId: opts.parentSubagentId } : {},
1133
+ ...parentSessionId !== undefined ? { parentSessionId } : {}
1134
+ };
1135
+ opts.parentBus?.emit("subagent-spawn", {
1136
+ ...lifecycleBase,
1137
+ name: opts.subagentName,
1138
+ input: opts.lifecycleInput
1139
+ });
1140
+ let handle;
1141
+ try {
1142
+ const childBus = new AgentEventBus;
1143
+ AgentEventBus.attachChild(childBus, opts.parentBus, childId);
1144
+ const spec = opts.spec.type === "pentest" && !opts.spec.browserSession && this.browser ? {
1145
+ ...opts.spec,
1146
+ browserSession: this.browser.forChild({
1147
+ subagentId: childId,
1148
+ subagentName: opts.subagentName
1149
+ })
1150
+ } : opts.spec;
1151
+ const runner = RUNNERS[spec.type];
1152
+ handle = await runner(spec, {
1153
+ ...opts.runtime,
1154
+ eventBus: childBus,
1155
+ subagentId: childId,
1156
+ subagentName: opts.subagentName
1157
+ });
1158
+ opts.beforeConsume?.(childBus);
1159
+ const result = await (opts.parentToolCallId && parentSessionId ? runWithNativeRolloutSession({
1160
+ sessionId: childId,
1161
+ parentSessionId,
1162
+ parentToolCallId: opts.parentToolCallId
1163
+ }, handle.run) : handle.run());
1164
+ await opts.onConsumed?.(result);
1165
+ if (opts.drainGraceMs != null) {
1166
+ await drainBounded(handle.drained?.(), opts.drainGraceMs);
1167
+ }
1168
+ opts.parentBus?.emit("subagent-complete", {
1169
+ ...lifecycleBase,
1170
+ status: opts.resolveStatus?.(result) ?? "completed"
1171
+ });
1172
+ return result;
1173
+ } catch (error) {
1174
+ try {
1175
+ await opts.onError?.(error);
1176
+ if (opts.drainGraceMs != null) {
1177
+ await drainBounded(handle?.drained?.(), opts.drainGraceMs);
1178
+ }
1179
+ } finally {
1180
+ opts.parentBus?.emit("subagent-complete", {
1181
+ ...lifecycleBase,
1182
+ status: "failed"
1183
+ });
1184
+ }
1185
+ throw error;
1186
+ }
1187
+ }
1188
+ spawnMany(items, worker, opts) {
1189
+ return runWithBoundedConcurrency(items, opts.concurrency, worker, opts.abortSignal);
1190
+ }
1191
+ }
1192
+ var inProcessSubagentSpawner2 = new InProcessSubagentSpawner;
1193
+ export { AgentEventBus, FindingsRegistry, inMemoryRegistryProvider, withFindingPersistedHook, assertDepth, inProcessSeams, resolveItemHooks, spawnBatch2, inProcessSubagentSpawner2 };