@probelabs/visor 0.1.182-ee → 0.1.183-ee

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 (205) hide show
  1. package/defaults/assistant.yaml +2 -1
  2. package/defaults/code-talk.yaml +6 -0
  3. package/defaults/skills/task-progress.yaml +39 -0
  4. package/dist/agent-protocol/task-evaluator.d.ts +2 -1
  5. package/dist/agent-protocol/task-evaluator.d.ts.map +1 -1
  6. package/dist/agent-protocol/task-progress-tool.d.ts +29 -0
  7. package/dist/agent-protocol/task-progress-tool.d.ts.map +1 -0
  8. package/dist/agent-protocol/task-store.d.ts +8 -0
  9. package/dist/agent-protocol/task-store.d.ts.map +1 -1
  10. package/dist/agent-protocol/tasks-cli-handler.d.ts.map +1 -1
  11. package/dist/agent-protocol/trace-serializer.d.ts +5 -2
  12. package/dist/agent-protocol/trace-serializer.d.ts.map +1 -1
  13. package/dist/agent-protocol/track-execution.d.ts +1 -1
  14. package/dist/agent-protocol/track-execution.d.ts.map +1 -1
  15. package/dist/ai-review-service.d.ts.map +1 -1
  16. package/dist/cli-main.d.ts.map +1 -1
  17. package/dist/debug-visualizer/trace-reader.d.ts.map +1 -1
  18. package/dist/defaults/assistant.yaml +2 -1
  19. package/dist/defaults/code-talk.yaml +6 -0
  20. package/dist/defaults/skills/task-progress.yaml +39 -0
  21. package/dist/docs/telemetry-live-spans-plan.md +510 -0
  22. package/dist/generated/config-schema.json +43 -6
  23. package/dist/index.js +3545 -701
  24. package/dist/providers/ai-check-provider.d.ts.map +1 -1
  25. package/dist/providers/git-checkout-provider.d.ts.map +1 -1
  26. package/dist/providers/mcp-custom-sse-server.d.ts.map +1 -1
  27. package/dist/reviewer.d.ts +2 -0
  28. package/dist/reviewer.d.ts.map +1 -1
  29. package/dist/runners/process-cli-handler.d.ts +2 -0
  30. package/dist/runners/process-cli-handler.d.ts.map +1 -0
  31. package/dist/runners/process-discovery.d.ts +29 -0
  32. package/dist/runners/process-discovery.d.ts.map +1 -0
  33. package/dist/sandbox/check-runner.d.ts.map +1 -1
  34. package/dist/sandbox/sandbox-telemetry.d.ts +7 -0
  35. package/dist/sandbox/sandbox-telemetry.d.ts.map +1 -1
  36. package/dist/sandbox/trace-ingester.d.ts +28 -15
  37. package/dist/sandbox/trace-ingester.d.ts.map +1 -1
  38. package/dist/scheduler/schedule-tool.d.ts +5 -0
  39. package/dist/scheduler/schedule-tool.d.ts.map +1 -1
  40. package/dist/sdk/{a2a-frontend-MU5EO2HZ.mjs → a2a-frontend-5YDHFQXD.mjs} +47 -8
  41. package/dist/sdk/{a2a-frontend-MU5EO2HZ.mjs.map → a2a-frontend-5YDHFQXD.mjs.map} +1 -1
  42. package/dist/sdk/{a2a-frontend-4LP3MLTS.mjs → a2a-frontend-6LWBIPMS.mjs} +19 -3
  43. package/dist/sdk/a2a-frontend-6LWBIPMS.mjs.map +1 -0
  44. package/dist/sdk/check-provider-registry-WSEVHJEV.mjs +31 -0
  45. package/dist/sdk/{check-provider-registry-I4BCWKRU.mjs → check-provider-registry-YRADEEQY.mjs} +6 -6
  46. package/dist/sdk/chunk-4BN2XI4X.mjs +459 -0
  47. package/dist/sdk/chunk-4BN2XI4X.mjs.map +1 -0
  48. package/dist/sdk/chunk-54KOAC4W.mjs +665 -0
  49. package/dist/sdk/chunk-54KOAC4W.mjs.map +1 -0
  50. package/dist/sdk/chunk-6C3R6E42.mjs +1700 -0
  51. package/dist/sdk/chunk-6C3R6E42.mjs.map +1 -0
  52. package/dist/sdk/{chunk-4I3TJ7UJ.mjs → chunk-7W5QCO4Y.mjs} +47 -10
  53. package/dist/sdk/chunk-7W5QCO4Y.mjs.map +1 -0
  54. package/dist/sdk/chunk-B2OUZAWY.mjs +237 -0
  55. package/dist/sdk/chunk-B2OUZAWY.mjs.map +1 -0
  56. package/dist/sdk/chunk-FWWLD555.mjs +244 -0
  57. package/dist/sdk/chunk-FWWLD555.mjs.map +1 -0
  58. package/dist/sdk/{chunk-QXT47ZHR.mjs → chunk-G7GSN3SK.mjs} +2 -2
  59. package/dist/sdk/{chunk-QXT47ZHR.mjs.map → chunk-G7GSN3SK.mjs.map} +1 -1
  60. package/dist/sdk/{chunk-DHETLQIX.mjs → chunk-GA2TYKSR.mjs} +5 -5
  61. package/dist/sdk/{chunk-6DPPP7LD.mjs → chunk-IDL3AA3G.mjs} +203 -42
  62. package/dist/sdk/chunk-IDL3AA3G.mjs.map +1 -0
  63. package/dist/sdk/chunk-MEB2TTIE.mjs +157 -0
  64. package/dist/sdk/chunk-MEB2TTIE.mjs.map +1 -0
  65. package/dist/sdk/{chunk-3JFK6KCD.mjs → chunk-MFXPJUUE.mjs} +150 -280
  66. package/dist/sdk/chunk-MFXPJUUE.mjs.map +1 -0
  67. package/dist/sdk/{chunk-KBGQJKIZ.mjs → chunk-NPSLGKXB.mjs} +3 -3
  68. package/dist/sdk/chunk-P2K4VOMU.mjs +825 -0
  69. package/dist/sdk/chunk-P2K4VOMU.mjs.map +1 -0
  70. package/dist/sdk/chunk-RI4ONH5X.mjs +482 -0
  71. package/dist/sdk/chunk-RI4ONH5X.mjs.map +1 -0
  72. package/dist/sdk/chunk-S5FSRHMY.mjs +139 -0
  73. package/dist/sdk/chunk-S5FSRHMY.mjs.map +1 -0
  74. package/dist/sdk/{chunk-7ERVRLDV.mjs → chunk-TFUQ2D5L.mjs} +13 -2
  75. package/dist/sdk/chunk-TFUQ2D5L.mjs.map +1 -0
  76. package/dist/sdk/{chunk-TQQNSHQV.mjs → chunk-UXB4XWEE.mjs} +1044 -179
  77. package/dist/sdk/chunk-UXB4XWEE.mjs.map +1 -0
  78. package/dist/sdk/{chunk-U6K5SK7X.mjs → chunk-V45TITKX.mjs} +2 -2
  79. package/dist/sdk/{chunk-ANUT54HW.mjs → chunk-WKLJ57WF.mjs} +6 -6
  80. package/dist/sdk/chunk-XOAEKFKB.mjs +1150 -0
  81. package/dist/sdk/chunk-XOAEKFKB.mjs.map +1 -0
  82. package/dist/sdk/chunk-ZPYODGYA.mjs +251 -0
  83. package/dist/sdk/chunk-ZPYODGYA.mjs.map +1 -0
  84. package/dist/sdk/command-executor-YNJOS77A.mjs +14 -0
  85. package/dist/sdk/{config-2STD74CJ.mjs → config-PCP6O6Y6.mjs} +4 -4
  86. package/dist/sdk/{failure-condition-evaluator-FFWJRAEQ.mjs → failure-condition-evaluator-H3PBFBYT.mjs} +4 -4
  87. package/dist/sdk/failure-condition-evaluator-IRFKTYZD.mjs +18 -0
  88. package/dist/sdk/github-auth-BJQBLK2V.mjs +196 -0
  89. package/dist/sdk/github-auth-BJQBLK2V.mjs.map +1 -0
  90. package/dist/sdk/{github-frontend-L3F5JXPJ.mjs → github-frontend-DECYOBRN.mjs} +8 -8
  91. package/dist/sdk/{github-frontend-KGV2R5Z6.mjs → github-frontend-TZRBOQCN.mjs} +4 -4
  92. package/dist/sdk/{host-QBJ7TOWG.mjs → host-CFM2ASDI.mjs} +4 -4
  93. package/dist/sdk/{host-X5ZZCEWN.mjs → host-T4LNVU2H.mjs} +3 -3
  94. package/dist/sdk/{knex-store-QCEW4I4R.mjs → knex-store-OEWSZEBY.mjs} +3 -3
  95. package/dist/sdk/lazy-otel-5RDTVS5L.mjs +24 -0
  96. package/dist/sdk/liquid-extensions-E3AKRX7P.mjs +25 -0
  97. package/dist/sdk/{loader-ZNKKJEZ3.mjs → loader-WRGI244P.mjs} +5 -5
  98. package/dist/sdk/memory-store-OHUIXCWJ.mjs +12 -0
  99. package/dist/sdk/metrics-MYUPQBBV.mjs +41 -0
  100. package/dist/sdk/{opa-policy-engine-QCSSIMUF.mjs → opa-policy-engine-IVMCGVNA.mjs} +3 -3
  101. package/dist/sdk/prompt-state-LN57DQF3.mjs +16 -0
  102. package/dist/sdk/renderer-schema-BT2IXMLW.mjs +51 -0
  103. package/dist/sdk/renderer-schema-BT2IXMLW.mjs.map +1 -0
  104. package/dist/sdk/routing-H2PQ57OA.mjs +26 -0
  105. package/dist/sdk/{routing-CVQT4KHX.mjs → routing-JMZ7HDCC.mjs} +5 -5
  106. package/dist/sdk/schedule-tool-2DPNSU63.mjs +37 -0
  107. package/dist/sdk/{schedule-tool-AECLFHSY.mjs → schedule-tool-4M45RK3E.mjs} +6 -6
  108. package/dist/sdk/{schedule-tool-handler-6QLZRTQA.mjs → schedule-tool-handler-KLHE2SOW.mjs} +6 -6
  109. package/dist/sdk/schedule-tool-handler-KLHE2SOW.mjs.map +1 -0
  110. package/dist/sdk/{schedule-tool-handler-J4NUETJ6.mjs → schedule-tool-handler-NBEO46RV.mjs} +16 -16
  111. package/dist/sdk/schedule-tool-handler-NBEO46RV.mjs.map +1 -0
  112. package/dist/sdk/sdk.d.mts +2 -0
  113. package/dist/sdk/sdk.d.ts +2 -0
  114. package/dist/sdk/sdk.js +3125 -666
  115. package/dist/sdk/sdk.js.map +1 -1
  116. package/dist/sdk/sdk.mjs +15 -15
  117. package/dist/sdk/slack-frontend-DF5VL4OF.mjs +929 -0
  118. package/dist/sdk/slack-frontend-DF5VL4OF.mjs.map +1 -0
  119. package/dist/sdk/{task-evaluator-HLNXKKVV.mjs → task-evaluator-GQYDOSGT.mjs} +138 -24
  120. package/dist/sdk/task-evaluator-GQYDOSGT.mjs.map +1 -0
  121. package/dist/sdk/task-evaluator-OVMG7S56.mjs +263 -0
  122. package/dist/sdk/task-evaluator-OVMG7S56.mjs.map +1 -0
  123. package/dist/sdk/{trace-helpers-WJXYVV4S.mjs → trace-helpers-26ZCAE2V.mjs} +7 -5
  124. package/dist/sdk/trace-helpers-26ZCAE2V.mjs.map +1 -0
  125. package/dist/sdk/{trace-helpers-3FFAI7X3.mjs → trace-helpers-XV5GAX5L.mjs} +3 -3
  126. package/dist/sdk/trace-helpers-XV5GAX5L.mjs.map +1 -0
  127. package/dist/sdk/{trace-reader-ZY77OFNM.mjs → trace-reader-OVE4DL2D.mjs} +6 -2
  128. package/dist/sdk/trace-reader-OVE4DL2D.mjs.map +1 -0
  129. package/dist/sdk/trace-serializer-KKBJHM7J.mjs +24 -0
  130. package/dist/sdk/trace-serializer-KKBJHM7J.mjs.map +1 -0
  131. package/dist/sdk/{track-execution-AMQQNXKE.mjs → track-execution-3EC24C2X.mjs} +68 -7
  132. package/dist/sdk/track-execution-3EC24C2X.mjs.map +1 -0
  133. package/dist/sdk/{track-execution-MKIQXP2C.mjs → track-execution-66RLL6QT.mjs} +10 -3
  134. package/dist/sdk/track-execution-66RLL6QT.mjs.map +1 -0
  135. package/dist/sdk/utcp-check-provider-WI3QZ3W6.mjs +16 -0
  136. package/dist/sdk/utcp-check-provider-WI3QZ3W6.mjs.map +1 -0
  137. package/dist/sdk/workflow-check-provider-X2UREEH7.mjs +31 -0
  138. package/dist/sdk/workflow-check-provider-X2UREEH7.mjs.map +1 -0
  139. package/dist/sdk/{workflow-check-provider-EXMC6JIS.mjs → workflow-check-provider-YXALZNAQ.mjs} +6 -6
  140. package/dist/sdk/workflow-check-provider-YXALZNAQ.mjs.map +1 -0
  141. package/dist/sdk/workflow-registry-YCZ3FCJC.mjs +12 -0
  142. package/dist/sdk/workflow-registry-YCZ3FCJC.mjs.map +1 -0
  143. package/dist/slack/socket-runner.d.ts.map +1 -1
  144. package/dist/state-machine/dispatch/sandbox-routing.d.ts.map +1 -1
  145. package/dist/state-machine/states/level-dispatch.d.ts.map +1 -1
  146. package/dist/telemetry/fallback-ndjson.d.ts +21 -0
  147. package/dist/telemetry/fallback-ndjson.d.ts.map +1 -1
  148. package/dist/telemetry/lazy-otel.d.ts +2 -0
  149. package/dist/telemetry/lazy-otel.d.ts.map +1 -1
  150. package/dist/telemetry/opentelemetry.d.ts +5 -0
  151. package/dist/telemetry/opentelemetry.d.ts.map +1 -1
  152. package/dist/telemetry/trace-helpers.d.ts +10 -0
  153. package/dist/telemetry/trace-helpers.d.ts.map +1 -1
  154. package/dist/test-runner/conversation-sugar.d.ts +7 -0
  155. package/dist/test-runner/conversation-sugar.d.ts.map +1 -1
  156. package/dist/test-runner/core/flow-stage.d.ts.map +1 -1
  157. package/dist/test-runner/index.d.ts.map +1 -1
  158. package/dist/test-runner/validator.d.ts.map +1 -1
  159. package/dist/types/git-checkout.d.ts +2 -0
  160. package/dist/types/git-checkout.d.ts.map +1 -1
  161. package/dist/utils/script-tool-environment.d.ts.map +1 -1
  162. package/package.json +2 -2
  163. package/dist/sdk/a2a-frontend-4LP3MLTS.mjs.map +0 -1
  164. package/dist/sdk/check-provider-registry-RRWCXSTG.mjs +0 -31
  165. package/dist/sdk/chunk-3JFK6KCD.mjs.map +0 -1
  166. package/dist/sdk/chunk-4I3TJ7UJ.mjs.map +0 -1
  167. package/dist/sdk/chunk-6DPPP7LD.mjs.map +0 -1
  168. package/dist/sdk/chunk-6VVXKXTI.mjs +0 -164
  169. package/dist/sdk/chunk-6VVXKXTI.mjs.map +0 -1
  170. package/dist/sdk/chunk-7ERVRLDV.mjs.map +0 -1
  171. package/dist/sdk/chunk-TQQNSHQV.mjs.map +0 -1
  172. package/dist/sdk/failure-condition-evaluator-5DZYMCGW.mjs +0 -18
  173. package/dist/sdk/routing-XALEDC2G.mjs +0 -26
  174. package/dist/sdk/schedule-tool-Z6QYL2B3.mjs +0 -37
  175. package/dist/sdk/task-evaluator-HLNXKKVV.mjs.map +0 -1
  176. package/dist/sdk/trace-reader-ZY77OFNM.mjs.map +0 -1
  177. package/dist/sdk/track-execution-AMQQNXKE.mjs.map +0 -1
  178. package/dist/sdk/track-execution-MKIQXP2C.mjs.map +0 -1
  179. package/dist/sdk/workflow-check-provider-VKYGI5GK.mjs +0 -31
  180. /package/dist/sdk/{check-provider-registry-I4BCWKRU.mjs.map → check-provider-registry-WSEVHJEV.mjs.map} +0 -0
  181. /package/dist/sdk/{check-provider-registry-RRWCXSTG.mjs.map → check-provider-registry-YRADEEQY.mjs.map} +0 -0
  182. /package/dist/sdk/{chunk-DHETLQIX.mjs.map → chunk-GA2TYKSR.mjs.map} +0 -0
  183. /package/dist/sdk/{chunk-ANUT54HW.mjs.map → chunk-NPSLGKXB.mjs.map} +0 -0
  184. /package/dist/sdk/{chunk-U6K5SK7X.mjs.map → chunk-V45TITKX.mjs.map} +0 -0
  185. /package/dist/sdk/{chunk-KBGQJKIZ.mjs.map → chunk-WKLJ57WF.mjs.map} +0 -0
  186. /package/dist/sdk/{config-2STD74CJ.mjs.map → command-executor-YNJOS77A.mjs.map} +0 -0
  187. /package/dist/sdk/{failure-condition-evaluator-5DZYMCGW.mjs.map → config-PCP6O6Y6.mjs.map} +0 -0
  188. /package/dist/sdk/{failure-condition-evaluator-FFWJRAEQ.mjs.map → failure-condition-evaluator-H3PBFBYT.mjs.map} +0 -0
  189. /package/dist/sdk/{routing-CVQT4KHX.mjs.map → failure-condition-evaluator-IRFKTYZD.mjs.map} +0 -0
  190. /package/dist/sdk/{github-frontend-KGV2R5Z6.mjs.map → github-frontend-DECYOBRN.mjs.map} +0 -0
  191. /package/dist/sdk/{github-frontend-L3F5JXPJ.mjs.map → github-frontend-TZRBOQCN.mjs.map} +0 -0
  192. /package/dist/sdk/{host-QBJ7TOWG.mjs.map → host-CFM2ASDI.mjs.map} +0 -0
  193. /package/dist/sdk/{host-X5ZZCEWN.mjs.map → host-T4LNVU2H.mjs.map} +0 -0
  194. /package/dist/sdk/{knex-store-QCEW4I4R.mjs.map → knex-store-OEWSZEBY.mjs.map} +0 -0
  195. /package/dist/sdk/{routing-XALEDC2G.mjs.map → lazy-otel-5RDTVS5L.mjs.map} +0 -0
  196. /package/dist/sdk/{schedule-tool-AECLFHSY.mjs.map → liquid-extensions-E3AKRX7P.mjs.map} +0 -0
  197. /package/dist/sdk/{loader-ZNKKJEZ3.mjs.map → loader-WRGI244P.mjs.map} +0 -0
  198. /package/dist/sdk/{schedule-tool-Z6QYL2B3.mjs.map → memory-store-OHUIXCWJ.mjs.map} +0 -0
  199. /package/dist/sdk/{schedule-tool-handler-6QLZRTQA.mjs.map → metrics-MYUPQBBV.mjs.map} +0 -0
  200. /package/dist/sdk/{opa-policy-engine-QCSSIMUF.mjs.map → opa-policy-engine-IVMCGVNA.mjs.map} +0 -0
  201. /package/dist/sdk/{schedule-tool-handler-J4NUETJ6.mjs.map → prompt-state-LN57DQF3.mjs.map} +0 -0
  202. /package/dist/sdk/{trace-helpers-3FFAI7X3.mjs.map → routing-H2PQ57OA.mjs.map} +0 -0
  203. /package/dist/sdk/{trace-helpers-WJXYVV4S.mjs.map → routing-JMZ7HDCC.mjs.map} +0 -0
  204. /package/dist/sdk/{workflow-check-provider-EXMC6JIS.mjs.map → schedule-tool-2DPNSU63.mjs.map} +0 -0
  205. /package/dist/sdk/{workflow-check-provider-VKYGI5GK.mjs.map → schedule-tool-4M45RK3E.mjs.map} +0 -0
@@ -0,0 +1 @@
1
+ {"version":3,"sources":["../../src/slack/client.ts","../../src/frontends/slack-frontend.ts"],"sourcesContent":["// Lightweight Slack Web API wrapper implemented with fetch (no external deps).\n// Only methods needed by SlackFrontend are implemented.\n\nexport class SlackClient {\n private token: string;\n\n constructor(botToken: string) {\n if (!botToken || typeof botToken !== 'string') {\n throw new Error('SlackClient: botToken is required');\n }\n this.token = botToken;\n }\n\n public readonly reactions = {\n add: async ({\n channel,\n timestamp,\n name,\n }: {\n channel: string;\n timestamp: string;\n name: string;\n }) => {\n const resp: any = await this.api('reactions.add', { channel, timestamp, name });\n if (!resp || resp.ok !== true) {\n // Non-fatal in CLI/test runs – log and continue\n const err = (resp && resp.error) || 'unknown_error';\n console.warn(`Slack reactions.add failed (non-fatal): ${err}`);\n return { ok: false as const };\n }\n return { ok: true } as const;\n },\n remove: async ({\n channel,\n timestamp,\n name,\n }: {\n channel: string;\n timestamp: string;\n name: string;\n }) => {\n const resp: any = await this.api('reactions.remove', { channel, timestamp, name });\n if (!resp || resp.ok !== true) {\n const err = (resp && resp.error) || 'unknown_error';\n console.warn(`Slack reactions.remove failed (non-fatal): ${err}`);\n return { ok: false as const };\n }\n return { ok: true } as const;\n },\n };\n\n public readonly chat = {\n postMessage: async ({\n channel,\n text,\n thread_ts,\n }: {\n channel: string;\n text: string;\n thread_ts?: string;\n }) => {\n try {\n const resp: any = await this.api('chat.postMessage', { channel, text, thread_ts });\n if (!resp || resp.ok !== true) {\n const err = (resp && resp.error) || 'unknown_error';\n const warnings = Array.isArray(resp?.response_metadata?.warnings)\n ? resp.response_metadata.warnings.join(',')\n : '';\n console.warn(\n `Slack chat.postMessage failed (non-fatal): error=${err} channel=${channel} thread_ts=${\n thread_ts || '-'\n } text_len=${text.length}${warnings ? ` warnings=${warnings}` : ''}`\n );\n return {\n ok: false as const,\n ts: undefined,\n message: undefined,\n data: resp,\n error: err,\n };\n }\n // Normalize common fields for tests/frontend\n return {\n ok: true as const,\n ts: resp.ts || (resp.message && resp.message.ts) || undefined,\n message: resp.message,\n data: resp,\n error: undefined,\n };\n } catch (e) {\n console.warn(\n `Slack chat.postMessage threw (non-fatal): channel=${channel} thread_ts=${thread_ts || '-'} text_len=${\n text.length\n } error=${e instanceof Error ? e.message : String(e)}`\n );\n return {\n ok: false as const,\n ts: undefined,\n message: undefined,\n data: undefined,\n error: e instanceof Error ? e.message : String(e),\n };\n }\n },\n update: async ({ channel, ts, text }: { channel: string; ts: string; text: string }) => {\n try {\n const resp: any = await this.api('chat.update', { channel, ts, text });\n if (!resp || resp.ok !== true) {\n const err = (resp && resp.error) || 'unknown_error';\n const warnings = Array.isArray(resp?.response_metadata?.warnings)\n ? resp.response_metadata.warnings.join(',')\n : '';\n console.warn(\n `Slack chat.update failed (non-fatal): error=${err} channel=${channel} ts=${ts} text_len=${\n text.length\n }${warnings ? ` warnings=${warnings}` : ''}`\n );\n return { ok: false as const, ts, error: err, data: resp };\n }\n return { ok: true as const, ts: resp.ts || ts, error: undefined, data: resp };\n } catch (e) {\n console.warn(\n `Slack chat.update threw (non-fatal): channel=${channel} ts=${ts} text_len=${text.length} error=${\n e instanceof Error ? e.message : String(e)\n }`\n );\n return {\n ok: false as const,\n ts,\n error: e instanceof Error ? e.message : String(e),\n data: undefined,\n };\n }\n },\n };\n\n async getBotUserId(): Promise<string> {\n const resp: any = await this.api('auth.test', {});\n if (!resp || resp.ok !== true || !resp.user_id) {\n console.warn('Slack auth.test failed (non-fatal); bot user id unavailable');\n return 'UNKNOWN_BOT';\n }\n return String(resp.user_id);\n }\n\n /**\n * Fetch user info from Slack API.\n * Returns user profile including guest status flags, email, display name, and timezone.\n */\n async getUserInfo(userId: string): Promise<{\n ok: boolean;\n user?: {\n id: string;\n name?: string; // username\n real_name?: string; // full name\n email?: string; // requires users:read.email scope\n is_restricted?: boolean; // Multi-channel guest\n is_ultra_restricted?: boolean; // Single-channel guest\n is_bot?: boolean;\n is_app_user?: boolean;\n deleted?: boolean;\n tz?: string; // IANA timezone (e.g., \"America/New_York\")\n tz_offset?: number; // Timezone offset in seconds from UTC\n };\n }> {\n try {\n const resp: any = await this.api('users.info', { user: userId });\n if (!resp || resp.ok !== true || !resp.user) {\n return { ok: false };\n }\n return {\n ok: true,\n user: {\n id: resp.user.id,\n name: resp.user.name,\n real_name: resp.user.real_name || resp.user.profile?.real_name,\n email: resp.user.profile?.email,\n is_restricted: resp.user.is_restricted,\n is_ultra_restricted: resp.user.is_ultra_restricted,\n is_bot: resp.user.is_bot,\n is_app_user: resp.user.is_app_user,\n deleted: resp.user.deleted,\n tz: resp.user.tz,\n tz_offset: resp.user.tz_offset,\n },\n };\n } catch (e) {\n console.warn(`Slack users.info failed: ${e instanceof Error ? e.message : String(e)}`);\n return { ok: false };\n }\n }\n\n /**\n * Open a DM channel with a user.\n * Returns the DM channel ID.\n */\n async openDM(userId: string): Promise<{ ok: boolean; channel?: string }> {\n try {\n const resp: any = await this.api('conversations.open', { users: userId });\n if (!resp || resp.ok !== true || !resp.channel?.id) {\n console.warn(`Slack conversations.open failed: ${resp?.error || 'unknown_error'}`);\n return { ok: false };\n }\n return { ok: true, channel: resp.channel.id };\n } catch (e) {\n console.warn(\n `Slack conversations.open failed: ${e instanceof Error ? e.message : String(e)}`\n );\n return { ok: false };\n }\n }\n\n async fetchThreadReplies(\n channel: string,\n thread_ts: string,\n limit: number = 40\n ): Promise<\n Array<{\n ts: string;\n user?: string;\n text?: string;\n bot_id?: string;\n thread_ts?: string;\n files?: any[];\n attachments?: any[];\n }>\n > {\n try {\n // Use query-string GET semantics similar to Slack WebClient to avoid\n // subtle JSON/form encoding issues that can cause invalid_arguments\n const params = new URLSearchParams({\n channel,\n ts: thread_ts,\n limit: String(limit),\n });\n const res = await fetch(`https://slack.com/api/conversations.replies?${params.toString()}`, {\n method: 'GET',\n headers: {\n Authorization: `Bearer ${this.token}`,\n },\n });\n const resp: any = await res.json();\n if (!resp || resp.ok !== true || !Array.isArray(resp.messages)) {\n const err = (resp && resp.error) || 'unknown_error';\n console.warn(\n `Slack conversations.replies failed (non-fatal): ${err} (channel=${channel}, ts=${thread_ts}, limit=${limit})`\n );\n return [];\n }\n return resp.messages.map((m: any) => ({\n ts: String(m.ts || ''),\n user: m.user,\n text: m.text,\n bot_id: m.bot_id,\n thread_ts: m.thread_ts,\n files: Array.isArray(m.files) ? m.files : undefined,\n attachments: Array.isArray(m.attachments) ? m.attachments : undefined,\n }));\n } catch (e) {\n console.warn(\n `Slack conversations.replies failed (non-fatal): ${\n e instanceof Error ? e.message : String(e)\n } (channel=${channel}, ts=${thread_ts}, limit=${limit})`\n );\n return [];\n }\n }\n\n public readonly files = {\n /**\n * Upload a file to Slack using files.uploadV2 API\n * @param options Upload options including file content, filename, channel, and thread_ts\n */\n uploadV2: async ({\n content,\n filename,\n channel,\n thread_ts,\n title,\n initial_comment,\n }: {\n content: Buffer;\n filename: string;\n channel: string;\n thread_ts?: string;\n title?: string;\n initial_comment?: string;\n }): Promise<{ ok: boolean; file?: { id: string; permalink?: string } }> => {\n try {\n // Step 1: Get upload URL (uses form-urlencoded — this endpoint rejects JSON bodies)\n const getUrlResp: any = await this.apiForm('files.getUploadURLExternal', {\n filename,\n length: String(content.length),\n });\n if (!getUrlResp || getUrlResp.ok !== true || !getUrlResp.upload_url) {\n console.warn(\n `Slack files.getUploadURLExternal failed: ${getUrlResp?.error || 'unknown'}`\n );\n return { ok: false };\n }\n\n // Step 2: Upload file content to the URL\n const uploadResp = await fetch(getUrlResp.upload_url, {\n method: 'POST',\n body: content,\n });\n if (!uploadResp.ok) {\n console.warn(`Slack file upload to URL failed: ${uploadResp.status}`);\n return { ok: false };\n }\n\n // Step 3: Complete the upload and share to channel\n const completeResp: any = await this.api('files.completeUploadExternal', {\n files: [{ id: getUrlResp.file_id, title: title || filename }],\n channel_id: channel,\n thread_ts,\n initial_comment,\n });\n if (!completeResp || completeResp.ok !== true) {\n console.warn(\n `Slack files.completeUploadExternal failed: ${completeResp?.error || 'unknown'}`\n );\n return { ok: false };\n }\n\n return {\n ok: true,\n file: completeResp.files?.[0] || { id: getUrlResp.file_id },\n };\n } catch (e) {\n console.warn(`Slack file upload failed: ${e instanceof Error ? e.message : String(e)}`);\n return { ok: false };\n }\n },\n };\n\n public readonly views = {\n publish: async ({\n user_id,\n view,\n }: {\n user_id: string;\n view: Record<string, unknown>;\n }): Promise<{ ok: boolean; error?: string }> => {\n try {\n const resp: any = await this.api('views.publish', { user_id, view });\n if (!resp || resp.ok !== true) {\n const err = (resp && resp.error) || 'unknown_error';\n console.warn(`Slack views.publish failed (non-fatal): ${err}`);\n return { ok: false, error: err };\n }\n return { ok: true };\n } catch (e) {\n console.warn(\n `Slack views.publish threw (non-fatal): ${e instanceof Error ? e.message : String(e)}`\n );\n return { ok: false, error: e instanceof Error ? e.message : String(e) };\n }\n },\n };\n\n getWebClient(): any {\n return {\n conversations: {\n history: async ({ channel, limit }: { channel: string; limit?: number }) =>\n (await this.api('conversations.history', { channel, limit })) as any,\n open: async ({ users }: { users: string }) =>\n (await this.api('conversations.open', { users })) as any,\n replies: async ({ channel, ts, limit }: { channel: string; ts: string; limit?: number }) =>\n (await this.api('conversations.replies', { channel, ts, limit })) as any,\n },\n };\n }\n\n private async api(method: string, body: Record<string, unknown>): Promise<unknown> {\n // Node 18+ global fetch\n const res = await fetch(`https://slack.com/api/${method}`, {\n method: 'POST',\n headers: {\n 'Content-Type': 'application/json; charset=utf-8',\n Authorization: `Bearer ${this.token}`,\n },\n body: JSON.stringify(body),\n });\n return (await res.json()) as unknown;\n }\n\n /** Send a Slack API request as application/x-www-form-urlencoded (required by some file methods). */\n private async apiForm(method: string, params: Record<string, string>): Promise<unknown> {\n const body = new URLSearchParams(params);\n const res = await fetch(`https://slack.com/api/${method}`, {\n method: 'POST',\n headers: {\n 'Content-Type': 'application/x-www-form-urlencoded',\n Authorization: `Bearer ${this.token}`,\n },\n body: body.toString(),\n });\n return (await res.json()) as unknown;\n }\n}\n","/**\n * Slack Frontend for Visor workflows.\n *\n * Features:\n * - Posts AI replies to Slack threads\n * - Converts Markdown to Slack mrkdwn format\n * - Renders mermaid diagrams to PNG and uploads as images\n * - Manages 👀/👍 reactions for acknowledgement\n * - Handles human input prompts via prompt-state\n *\n * Mermaid Diagram Rendering:\n * - Detects ```mermaid code blocks in AI responses\n * - Renders to PNG using @mermaid-js/mermaid-cli (mmdc)\n * - Uploads rendered images to Slack thread\n * - Replaces mermaid blocks with \"_(See diagram above)_\" placeholder\n *\n * Requirements for mermaid rendering:\n * - Node.js and npx in PATH\n * - Puppeteer/Chromium dependencies (mermaid-cli uses headless browser)\n * - On Linux: apt-get install chromium-browser libatk-bridge2.0-0 libgtk-3-0\n */\nimport type { Frontend, FrontendContext } from './host';\nimport { SlackClient } from '../slack/client';\nimport {\n formatSlackText,\n type MermaidDiagram,\n renderMermaidToPng,\n replaceMermaidBlocks,\n extractFileSections,\n replaceFileSections,\n} from '../slack/markdown';\nimport { context as otContext, trace } from '../telemetry/lazy-otel';\n\ntype SlackFrontendConfig = {\n defaultChannel?: string;\n groupChannels?: Record<string, string>;\n debounceMs?: number;\n maxWaitMs?: number;\n showRawOutput?: boolean;\n telemetry?: {\n enabled?: boolean;\n };\n};\n\nexport class SlackFrontend implements Frontend {\n public readonly name = 'slack';\n private subs: Array<{ unsubscribe(): void }> = [];\n private cfg: SlackFrontendConfig;\n // Reactions ack/done per run (inbound Slack events only)\n private acked: boolean = false;\n private ackRef: { channel: string; ts: string } | null = null;\n private ackName: string = 'eyes';\n private doneName: string = 'thumbsup';\n private errorNotified: boolean = false;\n private cachedTraceInfo: { traceId: string; spanId: string } | null = null;\n\n constructor(config?: SlackFrontendConfig) {\n this.cfg = config || {};\n }\n\n start(ctx: FrontendContext): void {\n const bus = ctx.eventBus;\n\n // Capture trace info now while the OTel span may still be active.\n // EventBus handlers run in a different async context where the span is lost.\n if (!this.cachedTraceInfo) {\n this.cachedTraceInfo = this.getTraceInfo();\n }\n // Also check ctx.run.traceId which is injected by the execution engine\n if (!this.cachedTraceInfo) {\n const runTraceId = (ctx as any)?.run?.traceId;\n if (typeof runTraceId === 'string' && runTraceId) {\n this.cachedTraceInfo = { traceId: runTraceId, spanId: '' };\n }\n }\n\n // Info-level boot log\n try {\n const hasClient = !!(\n (ctx as any).slack ||\n (ctx as any).slackClient ||\n (this.cfg as any)?.botToken ||\n process.env.SLACK_BOT_TOKEN\n );\n ctx.logger.info(`[slack-frontend] started; hasClient=${hasClient} defaultChannel=unset`);\n } catch {}\n\n // If this run was triggered by a Slack event, log key attributes\n try {\n const payload = this.getInboundSlackPayload(ctx);\n if (payload) {\n const ev: any = payload.event || {};\n const ch = String(ev.channel || '-');\n const ts = String(ev.ts || ev.event_ts || '-');\n const user = String(ev.user || ev.bot_id || '-');\n const type = String(ev.type || '-');\n const thread = String(ev.thread_ts || '');\n ctx.logger.info(\n `[slack-frontend] inbound event received: type=${type} channel=${ch} ts=${ts}` +\n (thread ? ` thread_ts=${thread}` : '') +\n ` user=${user}`\n );\n }\n } catch {}\n\n // Listen to check lifecycle; we only post on completion/error (no queued placeholders)\n this.subs.push(\n bus.on('CheckCompleted', async (env: any) => {\n const ev = (env && env.payload) || env;\n // For chat-style AI checks, post direct replies into the Slack thread\n await this.maybePostDirectReply(ctx, ev.checkId, ev.result).catch(() => {});\n // Post execution failure notices when a check completes with fatal issues\n await this.maybePostExecutionFailure(ctx, ev.checkId, ev.result).catch(() => {});\n })\n );\n this.subs.push(\n bus.on('CheckErrored', async (env: any) => {\n const ev = (env && env.payload) || env;\n const message = ev?.error?.message || 'Execution error';\n await this.maybePostError(ctx, 'Check failed', message, ev?.checkId).catch(() => {});\n })\n );\n\n // On terminal state, replace 👀 with 👍 if we acked an inbound Slack message.\n // For error states, always post an error notice (bypass errorNotified flag)\n // so the user is never left without feedback when a run fails.\n this.subs.push(\n bus.on('StateTransition', async (env: any) => {\n const ev = (env && env.payload) || env;\n if (ev && ev.to === 'Completed') {\n await this.finalizeReactions(ctx).catch(() => {});\n } else if (ev && ev.to === 'Error') {\n if (!this.errorNotified) {\n await this.maybePostError(ctx, 'Run failed', 'Workflow finished with errors').catch(\n () => {}\n );\n }\n await this.finalizeReactions(ctx).catch(() => {});\n }\n })\n );\n this.subs.push(\n bus.on('Shutdown', async (env: any) => {\n const ev = (env && env.payload) || env;\n const message = ev?.error?.message || 'Fatal error';\n // Always post shutdown errors — bypass errorNotified since a fatal\n // shutdown is critical and must reach the user even if a previous\n // (possibly unrelated) check already posted a non-fatal error.\n await this.forcePostError(ctx, 'Run failed', message).catch(() => {});\n })\n );\n // Add 👀 acknowledgement as soon as first check is scheduled for Slack-driven runs\n this.subs.push(\n bus.on('CheckScheduled', async () => {\n await this.ensureAcknowledgement(ctx).catch(() => {});\n })\n );\n\n // Human-input requests: post prompt to Slack and mark waiting using prompt-state\n this.subs.push(\n bus.on('HumanInputRequested', async (env: any) => {\n try {\n const ev = (env && env.payload) || env;\n if (!ev || typeof ev.prompt !== 'string' || !ev.checkId) return;\n // Determine channel/thread (Slack SocketMode); if we can't, just ignore.\n let channel = ev.channel as string | undefined;\n let threadTs = ev.threadTs as string | undefined;\n if (!channel || !threadTs) {\n const payload = this.getInboundSlackPayload(ctx);\n const e: any = payload?.event;\n const derivedTs = String(e?.thread_ts || e?.ts || e?.event_ts || '');\n const derivedCh = String(e?.channel || '');\n if (derivedCh && derivedTs) {\n channel = channel || derivedCh;\n threadTs = threadTs || derivedTs;\n }\n }\n if (!channel || !threadTs) return;\n\n // Mark waiting in prompt-state without posting the prompt text to Slack.\n const { getPromptStateManager } = await import('../slack/prompt-state');\n const mgr = getPromptStateManager();\n const prev = mgr.getWaiting(channel, threadTs);\n const text = String(ev.prompt);\n mgr.setWaiting(channel, threadTs, {\n checkName: String(ev.checkId),\n prompt: text,\n promptMessageTs: prev?.promptMessageTs,\n promptsPosted: ((prev?.promptsPosted || 0) + 1) as any,\n });\n try {\n ctx.logger.info(\n `[slack-frontend] registered human-input waiting state for ${channel} thread=${threadTs}`\n );\n } catch {}\n } catch (e) {\n try {\n ctx.logger.warn(\n `[slack-frontend] HumanInputRequested handling failed: ${\n e instanceof Error ? e.message : String(e)\n }`\n );\n } catch {}\n }\n })\n );\n\n // SnapshotSaved: attach snapshot path to waiting entry for this thread\n this.subs.push(\n bus.on('SnapshotSaved', async (env: any) => {\n try {\n const ev = (env && env.payload) || env;\n const channel = String(ev?.channel || '');\n const threadTs = String(ev?.threadTs || '');\n const filePath = String(ev?.filePath || '');\n if (!channel || !threadTs || !filePath) return;\n const { getPromptStateManager } = await import('../slack/prompt-state');\n const mgr = getPromptStateManager();\n mgr.update(channel, threadTs, { snapshotPath: filePath });\n try {\n ctx.logger.info(\n `[slack-frontend] snapshot path attached to waiting prompt: ${filePath}`\n );\n } catch {}\n } catch {}\n })\n );\n }\n\n stop(): void {\n for (const s of this.subs) s.unsubscribe();\n this.subs = [];\n }\n\n private getSlack(ctx: FrontendContext): any | undefined {\n // Prefer injected fake client in tests: ctx.slack or ctx.slackClient\n const injected = (ctx as any).slack || (ctx as any).slackClient;\n if (injected) return injected;\n // Else try to lazy-create from env or frontend config\n try {\n const token = (this.cfg as any)?.botToken || process.env.SLACK_BOT_TOKEN;\n if (typeof token === 'string' && token.trim()) {\n return new SlackClient(token.trim());\n }\n } catch {}\n return undefined;\n }\n\n private getInboundSlackPayload(ctx: FrontendContext): any | null {\n try {\n const anyCfg: any = ctx.config || {};\n const slackCfg: any = anyCfg.slack || {};\n const endpoint: string = slackCfg.endpoint || '/bots/slack/support';\n const payload: any = (ctx as any).webhookContext?.webhookData?.get(endpoint);\n return payload || null;\n } catch {\n return null;\n }\n }\n\n private getInboundSlackEvent(ctx: FrontendContext): { channel: string; ts: string } | null {\n try {\n const payload = this.getInboundSlackPayload(ctx);\n const ev: any = payload?.event;\n const channel = String(ev?.channel || '');\n const ts = String(ev?.ts || ev?.event_ts || '');\n if (channel && ts) return { channel, ts };\n } catch {}\n return null;\n }\n\n private isTelemetryEnabled(ctx: FrontendContext): boolean {\n try {\n const anyCfg: any = ctx.config || {};\n const slackCfg: any = anyCfg.slack || {};\n const telemetryCfg = slackCfg.telemetry ?? (this.cfg as any)?.telemetry;\n return (\n telemetryCfg === true ||\n (telemetryCfg && typeof telemetryCfg === 'object' && telemetryCfg.enabled === true)\n );\n } catch {\n return false;\n }\n }\n\n private async maybePostError(\n ctx: FrontendContext,\n title: string,\n message: string,\n checkId?: string\n ): Promise<void> {\n if (this.errorNotified) return;\n return this.postErrorToSlack(ctx, title, message, checkId);\n }\n\n /**\n * Post error to Slack regardless of errorNotified flag.\n * Used for fatal/shutdown errors that must always reach the user.\n */\n private async forcePostError(\n ctx: FrontendContext,\n title: string,\n message: string,\n checkId?: string\n ): Promise<void> {\n return this.postErrorToSlack(ctx, title, message, checkId);\n }\n\n private async postErrorToSlack(\n ctx: FrontendContext,\n title: string,\n message: string,\n checkId?: string\n ): Promise<void> {\n const slack = this.getSlack(ctx);\n if (!slack) return;\n const payload = this.getInboundSlackPayload(ctx);\n const ev: any = payload?.event;\n const channel = String(ev?.channel || '');\n const threadTs = String(ev?.thread_ts || ev?.ts || ev?.event_ts || '');\n if (!channel || !threadTs) {\n try {\n ctx.logger.warn(\n `[slack-frontend] skip posting error notice: missing channel/thread (channel=${\n channel || '-'\n } thread=${threadTs || '-'})`\n );\n } catch {}\n return;\n }\n\n let text = `❌ ${title}`;\n if (checkId) text += `\\nCheck: ${checkId}`;\n if (message) text += `\\n${message}`;\n\n if (this.isTelemetryEnabled(ctx)) {\n const traceInfo = this.getTraceInfo() || this.cachedTraceInfo;\n if (traceInfo?.traceId) {\n text += `\\n\\n\\`trace_id: ${traceInfo.traceId}\\``;\n }\n }\n\n const formattedText = formatSlackText(text);\n const postResult = await slack.chat.postMessage({\n channel,\n text: formattedText,\n thread_ts: threadTs,\n });\n if (!postResult?.ok) {\n try {\n ctx.logger.warn(\n `[slack-frontend] failed to post error notice to ${channel} thread=${threadTs} check=${\n checkId || 'run'\n } error=${postResult?.error || 'unknown_error'}`\n );\n } catch {}\n return;\n }\n try {\n ctx.logger.info(\n `[slack-frontend] posted error notice to ${channel} thread=${threadTs} check=${checkId || 'run'}`\n );\n } catch {}\n this.errorNotified = true;\n }\n\n private isExecutionFailureIssue(issue: any): boolean {\n const ruleId = String(issue?.ruleId || '');\n const msg = String(issue?.message || '');\n const msgLower = msg.toLowerCase();\n return (\n ruleId.endsWith('/error') ||\n ruleId.includes('/execution_error') ||\n ruleId.includes('timeout') ||\n ruleId.includes('sandbox_runner_error') ||\n msgLower.includes('timed out') ||\n msg.includes('Command execution failed')\n );\n }\n\n private async maybePostExecutionFailure(\n ctx: FrontendContext,\n checkId: string,\n result: { issues?: any[] }\n ): Promise<void> {\n try {\n if (this.errorNotified) return;\n const cfg: any = ctx.config || {};\n const checkCfg: any = cfg.checks?.[checkId];\n if (!checkCfg) return;\n if (checkCfg.type === 'human-input') return;\n // Don't suppress execution failures for internal checks — timeouts and\n // errors on steps like generate-response must still reach the user.\n const issues = (result as any)?.issues;\n if (!Array.isArray(issues) || issues.length === 0) return;\n\n const failureIssue = issues.find(issue => this.isExecutionFailureIssue(issue));\n if (!failureIssue) return;\n if (\n typeof failureIssue.message === 'string' &&\n failureIssue.message.toLowerCase().includes('awaiting human input')\n ) {\n return;\n }\n\n const msg =\n typeof failureIssue.message === 'string' && failureIssue.message.trim().length > 0\n ? failureIssue.message.trim()\n : `Execution failed (${String(failureIssue.ruleId || 'unknown')})`;\n await this.maybePostError(ctx, 'Check failed', msg, checkId);\n } catch {}\n }\n\n private async ensureAcknowledgement(ctx: FrontendContext): Promise<void> {\n if (this.acked) return;\n const ref = this.getInboundSlackEvent(ctx);\n if (!ref) return;\n const slack = this.getSlack(ctx);\n if (!slack) return;\n // Skip ack for our own bot messages to avoid loops (allow other bots)\n try {\n const payload = this.getInboundSlackPayload(ctx);\n const ev: any = payload?.event;\n // If we can resolve bot user id, skip if the sender is the bot\n try {\n const botId = await slack.getBotUserId?.();\n if (botId && ev?.user && String(ev.user) === String(botId)) return;\n } catch {}\n } catch {}\n // Allow overrides via config\n try {\n const anyCfg: any = ctx.config || {};\n const slackCfg: any = anyCfg.slack || {};\n if (slackCfg?.reactions?.enabled === false) return;\n this.ackName = slackCfg?.reactions?.ack || this.ackName;\n this.doneName = slackCfg?.reactions?.done || this.doneName;\n } catch {}\n await slack.reactions.add({ channel: ref.channel, timestamp: ref.ts, name: this.ackName });\n try {\n ctx.logger.info(\n `[slack-frontend] added acknowledgement reaction :${this.ackName}: channel=${ref.channel} ts=${ref.ts}`\n );\n } catch {}\n this.acked = true;\n this.ackRef = ref;\n // Capture trace info while span is active (event handlers lose OTel context)\n if (!this.cachedTraceInfo) {\n this.cachedTraceInfo = this.getTraceInfo();\n }\n }\n\n private async finalizeReactions(ctx: FrontendContext): Promise<void> {\n if (!this.acked || !this.ackRef) return;\n const slack = this.getSlack(ctx);\n if (!slack) return;\n try {\n try {\n await slack.reactions.remove({\n channel: this.ackRef.channel,\n timestamp: this.ackRef.ts,\n name: this.ackName,\n });\n } catch {}\n await slack.reactions.add({\n channel: this.ackRef.channel,\n timestamp: this.ackRef.ts,\n name: this.doneName,\n });\n try {\n ctx.logger.info(\n `[slack-frontend] replaced acknowledgement with completion reaction :${this.doneName}: channel=${this.ackRef.channel} ts=${this.ackRef.ts}`\n );\n } catch {}\n } finally {\n // Reset for safety\n this.acked = false;\n this.ackRef = null;\n }\n }\n\n /**\n * Post direct replies into the originating Slack thread when appropriate.\n * This is independent of summary messages and is intended for chat-style flows\n * (e.g., AI answers and explicit chat/notify steps).\n */\n private async maybePostDirectReply(\n ctx: FrontendContext,\n checkId: string,\n result: { output?: any; content?: string }\n ): Promise<void> {\n try {\n const cfg: any = ctx.config || {};\n const checkCfg: any = cfg.checks?.[checkId];\n if (!checkCfg) return;\n\n // Per-workflow / per-frontend flag to allow posting raw JSON\n // outputs for AI steps (useful for debugging router outputs).\n const slackRoot: any = (cfg as any).slack || {};\n const showRawOutput =\n slackRoot.show_raw_output === true || (this.cfg as any)?.showRawOutput === true;\n const telemetryCfg = slackRoot.telemetry ?? (this.cfg as any)?.telemetry;\n\n const providerType = (checkCfg.type as string) || '';\n const isAi = providerType === 'ai';\n const isLogChat = providerType === 'log' && checkCfg.group === 'chat';\n const isWorkflow = providerType === 'workflow';\n\n // Allow ai, log-chat, and workflow types; skip everything else\n if (!isAi && !isLogChat && !isWorkflow) return;\n\n // Skip internal steps - they're intermediate processing and shouldn't post to Slack\n if (checkCfg.criticality === 'internal') return;\n\n // For AI checks, only post when using simple/unstructured schemas (or none).\n if (isAi) {\n const schema = checkCfg.schema;\n // String schemas: allow only simple/plain ones\n if (typeof schema === 'string') {\n const simpleSchemas = ['code-review', 'markdown', 'text', 'plain'];\n if (!simpleSchemas.includes(schema)) return;\n }\n // Object schemas (custom JSON): treat as structured; require output.text\n }\n\n const slack = this.getSlack(ctx);\n if (!slack) return;\n\n const payload = this.getInboundSlackPayload(ctx);\n const ev: any = payload?.event;\n const channel = String(ev?.channel || '');\n const threadTs = String(ev?.thread_ts || ev?.ts || ev?.event_ts || '');\n if (!channel || !threadTs) {\n ctx.logger.warn(\n `[slack-frontend] skip posting AI reply for ${checkId}: missing channel/thread (channel=${\n channel || '-'\n } thread=${threadTs || '-'})`\n );\n return;\n }\n\n // Prefer output.text; fall back to content ONLY for string/simple schemas.\n const out: any = (result as any)?.output;\n let text: string | undefined;\n if (out && typeof out.text === 'string' && out.text.trim().length > 0) {\n text = out.text.trim();\n } else if (isAi && typeof checkCfg.schema === 'string') {\n if (\n typeof (result as any)?.content === 'string' &&\n (result as any).content.trim().length > 0\n ) {\n text = (result as any).content.trim();\n }\n } else if (isLogChat && typeof (result as any)?.logOutput === 'string') {\n // For log-based chat checks, render the formatted log output as the\n // Slack message when no structured text field is present.\n const raw = (result as any).logOutput;\n if (raw.trim().length > 0) {\n text = raw.trim();\n }\n } else if (isAi && showRawOutput && out !== undefined) {\n try {\n text = JSON.stringify(out, null, 2);\n } catch {\n text = String(out);\n }\n }\n // Append raw output from DSL execute_plan (bypasses LLM rewriting chain)\n if (out && typeof out._rawOutput === 'string' && out._rawOutput.trim().length > 0) {\n text = (text || '') + '\\n\\n' + out._rawOutput.trim();\n }\n\n // Fallback: if no text was extracted, check for error issues (e.g. timeout)\n // and post an error message so the user isn't left with silence.\n if (!text) {\n const issues: any[] = (result as any)?.issues || [];\n const errorIssues = issues.filter(\n (i: any) =>\n i.severity === 'error' &&\n (i.ruleId?.startsWith('system/') || i.ruleId?.endsWith('/error'))\n );\n if (errorIssues.length > 0) {\n const errorMessages = errorIssues.map((i: any) => i.message).join('\\n');\n text = `:warning: Something went wrong while processing your request:\\n${errorMessages}`;\n // Prevent maybePostExecutionFailure from double-posting the same error\n this.errorNotified = true;\n ctx.logger.warn(\n `[slack-frontend] posting error fallback for ${checkId}: ${errorIssues.length} system error(s)`\n );\n }\n }\n\n if (!text) {\n ctx.logger.info(\n `[slack-frontend] skip posting AI reply for ${checkId}: no renderable text in check output`\n );\n return;\n }\n\n // Mermaid rendering is temporarily disabled — mmdc/puppeteer is too\n // heavy for the current deployment and frequently times out.\n // TODO: re-enable once a lighter renderer (e.g. kroki) is available.\n const diagrams: MermaidDiagram[] = []; // was: extractMermaidDiagrams(text);\n let processedText = text;\n\n if (diagrams.length > 0) {\n try {\n ctx.logger.info(\n `[slack-frontend] found ${diagrams.length} mermaid diagram(s) to render for ${checkId}`\n );\n } catch {}\n\n // Render and upload each diagram\n const uploadedCount: number[] = [];\n for (let i = 0; i < diagrams.length; i++) {\n const diagram = diagrams[i];\n try {\n ctx.logger.info(`[slack-frontend] rendering mermaid diagram ${i + 1}...`);\n const pngBuffer = await renderMermaidToPng(diagram.code);\n if (pngBuffer) {\n ctx.logger.info(\n `[slack-frontend] rendered diagram ${i + 1}, size=${pngBuffer.length} bytes, uploading...`\n );\n const filename = `diagram-${i + 1}.png`;\n const uploadResult = await slack.files.uploadV2({\n content: pngBuffer,\n filename,\n channel,\n thread_ts: threadTs,\n title: `Diagram ${i + 1}`,\n });\n if (uploadResult.ok) {\n uploadedCount.push(i);\n ctx.logger.info(`[slack-frontend] uploaded mermaid diagram ${i + 1} to ${channel}`);\n } else {\n ctx.logger.warn(`[slack-frontend] upload failed for diagram ${i + 1}`);\n }\n } else {\n ctx.logger.warn(\n `[slack-frontend] mermaid rendering returned null for diagram ${i + 1} (mmdc failed or not installed)`\n );\n }\n } catch (e) {\n ctx.logger.warn(\n `[slack-frontend] failed to render/upload mermaid diagram ${i + 1}: ${\n e instanceof Error ? e.message : String(e)\n }`\n );\n }\n }\n\n // Replace mermaid blocks with placeholder text\n if (uploadedCount.length > 0) {\n processedText = replaceMermaidBlocks(text, diagrams, idx =>\n uploadedCount.includes(idx) ? '_(See diagram above)_' : '_(Diagram rendering failed)_'\n );\n }\n }\n\n // Normalize literal \\n escape sequences from DSL output buffer before extraction.\n // AI-generated DSL code often writes \"\\\\n\" producing literal backslash-n instead of\n // actual newlines, which prevents the --- delimiter --- from matching on its own line.\n processedText = processedText.replace(/\\\\n/g, '\\n');\n\n // Extract and upload file sections (--- filename.ext --- delimiters)\n const fileSections = extractFileSections(processedText);\n if (fileSections.length > 0) {\n const uploadedFileIndices: number[] = [];\n for (let i = 0; i < fileSections.length; i++) {\n const section = fileSections[i];\n try {\n const buffer = Buffer.from(section.content, 'utf-8');\n const uploadResult = await slack.files.uploadV2({\n content: buffer,\n filename: section.filename,\n channel,\n thread_ts: threadTs,\n title: section.filename,\n });\n if (uploadResult.ok) {\n uploadedFileIndices.push(i);\n ctx.logger.info(`[slack-frontend] uploaded file ${section.filename} to ${channel}`);\n } else {\n ctx.logger.warn(`[slack-frontend] upload failed for file ${section.filename}`);\n }\n } catch (e) {\n ctx.logger.warn(\n `[slack-frontend] failed to upload file ${section.filename}: ${\n e instanceof Error ? e.message : String(e)\n }`\n );\n }\n }\n processedText = replaceFileSections(processedText, fileSections, idx =>\n uploadedFileIndices.includes(idx)\n ? `_(See file: ${fileSections[idx].filename} above)_`\n : `_(File upload failed: ${fileSections[idx].filename})_`\n );\n }\n\n let decoratedText = processedText;\n const telemetryEnabled =\n telemetryCfg === true ||\n (telemetryCfg && typeof telemetryCfg === 'object' && telemetryCfg.enabled === true);\n if (telemetryEnabled) {\n const traceInfo = this.getTraceInfo() || this.cachedTraceInfo;\n if (traceInfo?.traceId) {\n const suffix = `\\`trace_id: ${traceInfo.traceId}\\``;\n decoratedText = `${decoratedText}\\n\\n${suffix}`;\n }\n }\n\n const formattedText = formatSlackText(decoratedText);\n const postResult = await slack.chat.postMessage({\n channel,\n text: formattedText,\n thread_ts: threadTs,\n });\n if (!postResult?.ok) {\n ctx.logger.warn(\n `[slack-frontend] failed to post AI reply for ${checkId} to ${channel} thread=${threadTs} error=${\n postResult?.error || 'unknown_error'\n }`\n );\n return;\n }\n ctx.logger.info(\n `[slack-frontend] posted AI reply for ${checkId} to ${channel} thread=${threadTs} ts=${\n postResult.ts || '-'\n }`\n );\n\n // Capture response for scheduled reminders (allows storing previousResponse)\n const responseCapture = (ctx as any).responseCapture as ((text: string) => void) | undefined;\n if (responseCapture && typeof responseCapture === 'function') {\n try {\n // Store the original text (before mrkdwn formatting) for continuity\n responseCapture(processedText);\n } catch {}\n }\n } catch (outerErr) {\n // Log errors instead of silently swallowing them\n try {\n ctx.logger.warn(\n `[slack-frontend] maybePostDirectReply failed for ${checkId}: ${\n outerErr instanceof Error ? outerErr.message : String(outerErr)\n }`\n );\n } catch {}\n }\n }\n\n private getTraceInfo(): { traceId: string; spanId: string } | null {\n try {\n const span = trace.getSpan(otContext.active());\n if (!span) return null;\n const ctx = span.spanContext();\n if (!ctx || !ctx.traceId) return null;\n return { traceId: ctx.traceId, spanId: ctx.spanId };\n } catch {\n return null;\n }\n }\n}\n"],"mappings":"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","names":[]}
@@ -236,7 +236,7 @@ async function fetchFromLocalFiles(traceId, cfg) {
236
236
  const traceFile = await findTraceFile(traceId, cfg.traceDir);
237
237
  if (!traceFile) return null;
238
238
  try {
239
- const { parseNDJSONTrace } = await import("./trace-reader-ZY77OFNM.mjs");
239
+ const { parseNDJSONTrace } = await import("./trace-reader-OVE4DL2D.mjs");
240
240
  const trace = await parseNDJSONTrace(traceFile);
241
241
  return parseLocalNDJSONSpans(trace.spans);
242
242
  } catch (err) {
@@ -309,6 +309,7 @@ function buildSpanTree(spans) {
309
309
  nodeMap.set(span.spanId, { span, children: [] });
310
310
  }
311
311
  let root;
312
+ const orphans = [];
312
313
  for (const span of filtered) {
313
314
  const node = nodeMap.get(span.spanId);
314
315
  if (!span.parentSpanId) {
@@ -324,6 +325,8 @@ function buildSpanTree(spans) {
324
325
  if (parent) parent.children.push(node);
325
326
  } else if (!root) {
326
327
  root = node;
328
+ } else {
329
+ orphans.push(node);
327
330
  }
328
331
  }
329
332
  }
@@ -331,6 +334,9 @@ function buildSpanTree(spans) {
331
334
  const sorted = [...nodeMap.values()].sort((a, b) => b.span.durationMs - a.span.durationMs);
332
335
  root = sorted[0] || { span: filtered[0], children: [] };
333
336
  }
337
+ if (orphans.length > 0) {
338
+ root.children.push(...orphans);
339
+ }
334
340
  const sortChildren = (node) => {
335
341
  node.children.sort((a, b) => a.span.startTimeMs - b.span.startTimeMs);
336
342
  node.children.forEach(sortChildren);
@@ -385,13 +391,22 @@ function dedupeOrRegister(ctx, kind, text, spanName) {
385
391
  map.set(key, spanName);
386
392
  return null;
387
393
  }
388
- async function serializeTraceForPrompt(traceIdOrPath, maxChars, backendConfig, taskResponse) {
389
- let spans;
390
- if (traceIdOrPath.includes("/") || traceIdOrPath.endsWith(".ndjson")) {
391
- const { parseNDJSONTrace } = await import("./trace-reader-ZY77OFNM.mjs");
392
- const trace = await parseNDJSONTrace(traceIdOrPath);
393
- spans = parseLocalNDJSONSpans(trace.spans);
394
- } else {
394
+ async function serializeTraceForPrompt(traceIdOrPath, maxChars, backendConfig, taskResponse, fallbackTraceId) {
395
+ let spans = [];
396
+ const isFilePath = traceIdOrPath.includes("/") || traceIdOrPath.endsWith(".ndjson");
397
+ const remoteTraceId = fallbackTraceId || (!isFilePath ? traceIdOrPath : void 0);
398
+ if (remoteTraceId) {
399
+ spans = await fetchTraceSpans(remoteTraceId, backendConfig);
400
+ }
401
+ if (spans.length === 0 && isFilePath) {
402
+ try {
403
+ const { parseNDJSONTrace } = await import("./trace-reader-OVE4DL2D.mjs");
404
+ const trace = await parseNDJSONTrace(traceIdOrPath);
405
+ spans = parseLocalNDJSONSpans(trace.spans);
406
+ } catch {
407
+ }
408
+ }
409
+ if (spans.length === 0 && !remoteTraceId && !isFilePath) {
395
410
  spans = await fetchTraceSpans(traceIdOrPath, backendConfig);
396
411
  }
397
412
  if (spans.length === 0) {
@@ -456,9 +471,57 @@ function renderYamlNode(node, indent, lines, dedup, fallbackIntent, fullOutput,
456
471
  lines.push(`${pad}- ${tn}(${toolInput})${resultSize}${successMark}`);
457
472
  return;
458
473
  }
474
+ if (name === "search.delegate.dedup") {
475
+ const query = attrs["dedup.query"] || "";
476
+ const action = attrs["dedup.action"] || "?";
477
+ const reason = attrs["dedup.reason"] || "";
478
+ const rewritten = attrs["dedup.rewritten"] || "";
479
+ const prevCount = attrs["dedup.previous_count"] || "0";
480
+ let detail = `${action}`;
481
+ if (rewritten) detail += ` \u2192 "${truncate(String(rewritten), 60)}"`;
482
+ if (reason) detail += ` (${truncate(String(reason), 80)})`;
483
+ lines.push(
484
+ `${pad}dedup("${truncate(String(query), 60)}") [${prevCount} prior]: ${detail} \u2014 ${duration}`
485
+ );
486
+ return;
487
+ }
459
488
  if (name === "search.delegate") {
460
489
  const query = attrs["search.query"] || "";
461
- lines.push(`${pad}search.delegate("${truncate(String(query), 80)}") \u2014 ${duration}:`);
490
+ const rewritten = attrs["search.query.rewritten"] || "";
491
+ const output = attrs["search.delegate.output"] || "";
492
+ const outputLen = attrs["search.delegate.output_length"] || "";
493
+ let header = `search.delegate("${truncate(String(query), 80)}")`;
494
+ if (rewritten) header += ` \u2192 rewritten: "${truncate(String(rewritten), 60)}"`;
495
+ header += ` \u2014 ${duration}`;
496
+ lines.push(`${pad}${header}:`);
497
+ if (output) {
498
+ try {
499
+ const parsed = JSON.parse(String(output));
500
+ if (parsed.confidence) {
501
+ let confLine = `confidence: ${parsed.confidence}`;
502
+ if (parsed.reason) confLine += ` \u2014 ${truncate(String(parsed.reason), 100)}`;
503
+ lines.push(`${pad} ${confLine}`);
504
+ }
505
+ if (parsed.searches && Array.isArray(parsed.searches) && parsed.searches.length > 0) {
506
+ lines.push(`${pad} searches (${parsed.searches.length}):`);
507
+ for (const s of parsed.searches) {
508
+ const outcome = s.had_results ? "\u2713" : "\u2717";
509
+ lines.push(
510
+ `${pad} ${outcome} "${truncate(String(s.query || ""), 60)}" in ${truncate(String(s.path || "."), 40)}`
511
+ );
512
+ }
513
+ }
514
+ if (parsed.groups && Array.isArray(parsed.groups) && parsed.groups.length > 0) {
515
+ lines.push(`${pad} groups (${parsed.groups.length}):`);
516
+ for (const g of parsed.groups) {
517
+ const fileCount = g.files?.length || 0;
518
+ lines.push(`${pad} - ${truncate(String(g.reason || ""), 80)} (${fileCount} files)`);
519
+ }
520
+ }
521
+ } catch {
522
+ if (outputLen) lines.push(`${pad} output: ${outputLen} chars`);
523
+ }
524
+ }
462
525
  for (const child of node.children) {
463
526
  renderYamlNode(
464
527
  child,
@@ -617,8 +680,8 @@ function renderYamlOutput(rawOutput, pad, label, spanName, dedup, lines, fullOut
617
680
  obj = JSON.parse(rawOutput);
618
681
  } catch {
619
682
  obj = parseTruncatedJson(rawOutput);
620
- if (!obj || typeof obj !== "object") return;
621
683
  }
684
+ if (obj === null || obj === void 0 || typeof obj !== "object") return;
622
685
  if (typeof obj === "object" && !Array.isArray(obj)) {
623
686
  const keys = Object.keys(obj);
624
687
  if (keys.length === 1 && typeof obj[keys[0]] === "object" && obj[keys[0]] !== null) {
@@ -675,14 +738,16 @@ function renderYamlValue(val, pad, key, lines, fullOutput, maxLen, depth) {
675
738
  lines.push(`${pad}${key}: []`);
676
739
  return;
677
740
  }
741
+ if (val.every((v) => typeof v === "string") && val.join(", ").length < ml) {
742
+ lines.push(`${pad}${key}: [${val.join(", ")}]`);
743
+ return;
744
+ }
678
745
  const maxItems = fullOutput ? 20 : 3;
679
746
  lines.push(`${pad}${key}:`);
680
747
  for (let i = 0; i < Math.min(val.length, maxItems); i++) {
681
748
  const item = val[i];
682
749
  if (typeof item === "object" && item !== null) {
683
- const entries = Object.entries(item).filter(
684
- ([k]) => k !== "raw" && k !== "skills" && k !== "tags"
685
- );
750
+ const entries = Object.entries(item).filter(([k]) => k !== "raw" && k !== "tags");
686
751
  if (entries.length > 0) {
687
752
  const [firstKey, firstVal] = entries[0];
688
753
  if (firstVal === null || firstVal === void 0 || typeof firstVal !== "object") {
@@ -717,7 +782,7 @@ function renderYamlValue(val, pad, key, lines, fullOutput, maxLen, depth) {
717
782
  }
718
783
  lines.push(`${pad}${key}:`);
719
784
  for (const [k, v] of Object.entries(val)) {
720
- if (k === "raw" || k === "skills" || k === "tags") continue;
785
+ if (k === "raw" || k === "tags") continue;
721
786
  renderYamlValue(v, `${pad} `, k, lines, fullOutput, ml, d + 1);
722
787
  }
723
788
  }
@@ -778,6 +843,18 @@ function renderYamlInput(inputOutputsStr, pad, lines, fullOutput, maxLen, questi
778
843
  } catch {
779
844
  }
780
845
  }
846
+ function parseWorkspacePath(fullPath) {
847
+ const wsMatch = fullPath.match(/\/visor-workspaces\/[^/]+\/([^/]+)(?:\/(.+))?/);
848
+ if (wsMatch) {
849
+ return { repo: wsMatch[1], filePath: wsMatch[2] };
850
+ }
851
+ const wtMatch = fullPath.match(/\.visor\/worktrees\/worktrees\/[^/]+\/(.+)/);
852
+ if (wtMatch) {
853
+ const segs = wtMatch[1].split("/");
854
+ return { repo: segs[0], filePath: segs.length > 1 ? segs.slice(1).join("/") : void 0 };
855
+ }
856
+ return null;
857
+ }
781
858
  function extractToolInput(toolName, attrs) {
782
859
  const result = String(attrs["tool.result"] || "");
783
860
  const explicitInput = String(attrs["tool.input"] || "");
@@ -785,19 +862,43 @@ function extractToolInput(toolName, attrs) {
785
862
  switch (toolName) {
786
863
  case "search": {
787
864
  const patMatch = result.match(/Pattern: (.+)/);
788
- const pathMatch = result.match(/Path: \S+\/([^\s/]+)\s/);
865
+ const pathMatch = result.match(/Path: (\S+)/);
789
866
  const pattern = patMatch ? patMatch[1].trim() : "";
790
- const inPath = pathMatch ? pathMatch[1] : "";
791
- if (pattern && inPath) return `"${truncate(pattern, 50)}" in ${inPath}`;
792
- if (pattern) return `"${truncate(pattern, 60)}"`;
793
- return "";
867
+ const workspace = pathMatch ? parseWorkspacePath(pathMatch[1]) : null;
868
+ const parts = [];
869
+ if (pattern) parts.push(`"${truncate(pattern, 50)}"`);
870
+ if (workspace?.repo) parts.push(workspace.repo);
871
+ return parts.join(", ");
794
872
  }
795
873
  case "extract": {
796
874
  const fileMatch = result.match(/Files to extract:\n\s*(\S+)/);
797
875
  if (fileMatch) {
798
- const filePath = fileMatch[1];
799
- const parts = filePath.split("/");
800
- return parts.length > 2 ? parts.slice(-2).join("/") : parts[parts.length - 1];
876
+ const fullPath = fileMatch[1];
877
+ const workspace = parseWorkspacePath(fullPath);
878
+ if (workspace) {
879
+ const parts = [];
880
+ parts.push(workspace.filePath || workspace.repo || fullPath.split("/").pop() || "");
881
+ if (workspace.repo) parts.push(workspace.repo);
882
+ return parts.join(", ");
883
+ }
884
+ const segs = fullPath.split("/");
885
+ return segs.length > 2 ? segs.slice(-2).join("/") : segs[segs.length - 1];
886
+ }
887
+ return "";
888
+ }
889
+ case "bash": {
890
+ const cmdMatch = result.match(/^Command: (.+)/);
891
+ if (cmdMatch) {
892
+ let cmd = cmdMatch[1].trim();
893
+ const pipes = cmd.split(/\s*\|\s*/);
894
+ if (pipes.length > 2) {
895
+ cmd = `${pipes[0]} | ... (${pipes.length} stages)`;
896
+ }
897
+ return truncate(cmd, 80);
898
+ }
899
+ const deniedMatch = result.match(/^Permission denied: Component "([^"]+)"/);
900
+ if (deniedMatch) {
901
+ return truncate(deniedMatch[1], 60) + " [denied]";
801
902
  }
802
903
  return "";
803
904
  }
@@ -1124,7 +1225,8 @@ async function evaluateTask(taskId, store, config) {
1124
1225
  traceRef,
1125
1226
  1e6,
1126
1227
  { traceDir: config?.traceDir },
1127
- responseText !== "No response available" ? responseText : void 0
1228
+ responseText !== "No response available" ? responseText : void 0,
1229
+ traceId
1128
1230
  );
1129
1231
  if (traceTree === "(no trace data available)") {
1130
1232
  traceTree = void 0;
@@ -1189,6 +1291,16 @@ ${responseText}
1189
1291
  throw new Error(`Failed to parse evaluation response as JSON: ${response.slice(0, 200)}`);
1190
1292
  }
1191
1293
  }
1294
+ if (!hasTrace) {
1295
+ const MAX_RATING_WITHOUT_TRACE = 4;
1296
+ if (result.overall_rating > MAX_RATING_WITHOUT_TRACE) {
1297
+ result.overall_rating = MAX_RATING_WITHOUT_TRACE;
1298
+ }
1299
+ result.trace_available = false;
1300
+ result.summary = `[No trace available \u2014 execution quality not assessed, rating capped at ${MAX_RATING_WITHOUT_TRACE}/5] ${result.summary}`;
1301
+ } else {
1302
+ result.trace_available = true;
1303
+ }
1192
1304
  return result;
1193
1305
  }
1194
1306
  async function evaluateAndStore(taskId, store, config) {
@@ -1260,6 +1372,8 @@ The trace is a tree of spans representing the agent's execution pipeline:
1260
1372
  **Execution Quality** (1-5, only when trace is provided):
1261
1373
  - **Efficiency**: Were tool calls necessary and well-targeted? Good search queries that find results on the first try score high.
1262
1374
  - **Redundancy**: Were there duplicate searches, unnecessary re-searches with slightly different queries, or tools called for information already available?
1375
+ - **Extract-then-search anti-pattern**: If a file was already extracted (e.g., \`extract(docs/config.mdx) \u2192 3.3k chars\`), then a subsequent \`search("term" in config.mdx)\` is redundant \u2014 the agent already has the file content and should parse it from context instead of making another tool call. Flag every instance of this pattern.
1376
+ - **Search-reformulation waste**: If a search returns "no results" and the agent immediately retries with a minor query variation (e.g., \`"audit store_type"\` \u2192 \`"audit "store_type""\` \u2192 \`"store_type"\`), that's usually wasteful. A single well-crafted query should suffice; reformulating 3+ times for the same concept is a red flag.
1263
1377
  - **Delegation quality**: Were search delegations productive? Did they explore relevant code paths?
1264
1378
  - **Token usage**: Was input context kept reasonable, or did the agent load excessive amounts of code?
1265
1379
  - Rating: 5=efficient (minimal, targeted tool use), 4=adequate (minor redundancy), 3=some waste (noticeable unnecessary calls), 2=wasteful (many redundant searches or delegations), 1=error/broken execution
@@ -1275,4 +1389,4 @@ export {
1275
1389
  evaluateAndStore,
1276
1390
  evaluateTask
1277
1391
  };
1278
- //# sourceMappingURL=task-evaluator-HLNXKKVV.mjs.map
1392
+ //# sourceMappingURL=task-evaluator-GQYDOSGT.mjs.map