@equinor/fusion-framework-cli-plugin-copilot 2.0.2 → 2.0.3

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 (263) hide show
  1. package/CHANGELOG.md +10 -0
  2. package/dist/esm/commands/app/{session-logger.js → attach-session-logger.js} +16 -2
  3. package/dist/esm/commands/app/attach-session-logger.js.map +1 -0
  4. package/dist/esm/commands/app/{command.js → copilot-command.js} +22 -11
  5. package/dist/esm/commands/app/copilot-command.js.map +1 -0
  6. package/dist/esm/commands/app/{eval.js → create-session.js} +7 -5
  7. package/dist/esm/commands/app/create-session.js.map +1 -0
  8. package/dist/esm/commands/app/format-plan.js +24 -0
  9. package/dist/esm/commands/app/format-plan.js.map +1 -0
  10. package/dist/esm/commands/app/format-step-result.js +14 -0
  11. package/dist/esm/commands/app/format-step-result.js.map +1 -0
  12. package/dist/esm/commands/app/format-verdict.js +38 -0
  13. package/dist/esm/commands/app/format-verdict.js.map +1 -0
  14. package/dist/esm/commands/app/prompts/{system.dev-server.prompt.js → create-dev-server-context.js} +1 -1
  15. package/dist/esm/commands/app/prompts/create-dev-server-context.js.map +1 -0
  16. package/dist/esm/commands/app/prompts/{execute-step.prompt.js → create-execute-step-prompt.js} +1 -1
  17. package/dist/esm/commands/app/prompts/create-execute-step-prompt.js.map +1 -0
  18. package/dist/esm/commands/app/prompts/{judge.prompt.js → create-judge-prompt.js} +5 -1
  19. package/dist/esm/commands/app/prompts/create-judge-prompt.js.map +1 -0
  20. package/dist/esm/commands/app/prompts/{plan.prompt.js → create-plan-prompt.js} +1 -1
  21. package/dist/esm/commands/app/prompts/create-plan-prompt.js.map +1 -0
  22. package/dist/esm/commands/app/prompts/{step.prompt.js → create-step-prompt.js} +3 -2
  23. package/dist/esm/commands/app/prompts/create-step-prompt.js.map +1 -0
  24. package/dist/esm/commands/app/prompts/{system.prompt.js → create-system-prompt.js} +1 -1
  25. package/dist/esm/commands/app/prompts/create-system-prompt.js.map +1 -0
  26. package/dist/esm/commands/app/{login.js → run-login.js} +5 -1
  27. package/dist/esm/commands/app/run-login.js.map +1 -0
  28. package/dist/esm/commands/app/{server.js → start-app-server.js} +7 -1
  29. package/dist/esm/commands/app/start-app-server.js.map +1 -0
  30. package/dist/esm/commands/app/status-icon.js +18 -0
  31. package/dist/esm/commands/app/status-icon.js.map +1 -0
  32. package/dist/esm/commands/app/tools/{registry.js → AgentBrowserToolRegistry.js} +1 -1
  33. package/dist/esm/commands/app/tools/AgentBrowserToolRegistry.js.map +1 -0
  34. package/dist/esm/commands/app/tools/{write-file.js → create-append-file-tool.js} +5 -38
  35. package/dist/esm/commands/app/tools/create-append-file-tool.js.map +1 -0
  36. package/dist/esm/commands/app/tools/{click.js → create-click-tool.js} +1 -1
  37. package/dist/esm/commands/app/tools/create-click-tool.js.map +1 -0
  38. package/dist/esm/commands/app/tools/{errors.js → create-errors-tool.js} +1 -1
  39. package/dist/esm/commands/app/tools/create-errors-tool.js.map +1 -0
  40. package/dist/esm/commands/app/tools/{eval-js.js → create-eval-js-tool.js} +1 -1
  41. package/dist/esm/commands/app/tools/create-eval-js-tool.js.map +1 -0
  42. package/dist/esm/commands/app/tools/{fill.js → create-fill-tool.js} +1 -1
  43. package/dist/esm/commands/app/tools/create-fill-tool.js.map +1 -0
  44. package/dist/esm/commands/app/tools/{find.js → create-find-tool.js} +4 -1
  45. package/dist/esm/commands/app/tools/create-find-tool.js.map +1 -0
  46. package/dist/esm/commands/app/tools/{get-styles.js → create-get-styles-tool.js} +1 -1
  47. package/dist/esm/commands/app/tools/create-get-styles-tool.js.map +1 -0
  48. package/dist/esm/commands/app/tools/{get-url.js → create-get-url-tool.js} +1 -1
  49. package/dist/esm/commands/app/tools/create-get-url-tool.js.map +1 -0
  50. package/dist/esm/commands/app/tools/{go-back.js → create-go-back-tool.js} +1 -1
  51. package/dist/esm/commands/app/tools/create-go-back-tool.js.map +1 -0
  52. package/dist/esm/commands/app/tools/{hover.js → create-hover-tool.js} +1 -1
  53. package/dist/esm/commands/app/tools/create-hover-tool.js.map +1 -0
  54. package/dist/esm/commands/app/tools/{navigate.js → create-navigate-tool.js} +1 -1
  55. package/dist/esm/commands/app/tools/create-navigate-tool.js.map +1 -0
  56. package/dist/esm/commands/app/tools/{press-key.js → create-press-key-tool.js} +1 -1
  57. package/dist/esm/commands/app/tools/create-press-key-tool.js.map +1 -0
  58. package/dist/esm/commands/app/tools/{read-file.js → create-read-file-tool.js} +4 -2
  59. package/dist/esm/commands/app/tools/create-read-file-tool.js.map +1 -0
  60. package/dist/esm/commands/app/tools/{reload.js → create-reload-tool.js} +1 -1
  61. package/dist/esm/commands/app/tools/create-reload-tool.js.map +1 -0
  62. package/dist/esm/commands/app/tools/{screenshot.js → create-screenshot-tool.js} +7 -1
  63. package/dist/esm/commands/app/tools/create-screenshot-tool.js.map +1 -0
  64. package/dist/esm/commands/app/tools/{scroll.js → create-scroll-tool.js} +3 -1
  65. package/dist/esm/commands/app/tools/create-scroll-tool.js.map +1 -0
  66. package/dist/esm/commands/app/tools/{select.js → create-select-tool.js} +1 -1
  67. package/dist/esm/commands/app/tools/create-select-tool.js.map +1 -0
  68. package/dist/esm/commands/app/tools/{snapshot.js → create-snapshot-tool.js} +1 -1
  69. package/dist/esm/commands/app/tools/create-snapshot-tool.js.map +1 -0
  70. package/dist/esm/commands/app/tools/{type-text.js → create-type-text-tool.js} +1 -1
  71. package/dist/esm/commands/app/tools/create-type-text-tool.js.map +1 -0
  72. package/dist/esm/commands/app/tools/{wait.js → create-wait-tool.js} +5 -1
  73. package/dist/esm/commands/app/tools/create-wait-tool.js.map +1 -0
  74. package/dist/esm/commands/app/tools/create-write-file-tool.js +65 -0
  75. package/dist/esm/commands/app/tools/create-write-file-tool.js.map +1 -0
  76. package/dist/esm/commands/app/tools/index.js +19 -19
  77. package/dist/esm/commands/app/tools/index.js.map +1 -1
  78. package/dist/esm/commands/app/truncate.js +11 -0
  79. package/dist/esm/commands/app/truncate.js.map +1 -0
  80. package/dist/esm/commands/app/try-format-message.js +39 -0
  81. package/dist/esm/commands/app/try-format-message.js.map +1 -0
  82. package/dist/esm/exit-with-resolution-error.js +16 -0
  83. package/dist/esm/exit-with-resolution-error.js.map +1 -0
  84. package/dist/esm/index.js +1 -1
  85. package/dist/esm/index.js.map +1 -1
  86. package/dist/esm/resolve-eval-command-input.js +37 -0
  87. package/dist/esm/resolve-eval-command-input.js.map +1 -0
  88. package/dist/esm/resolve-eval-files.js +49 -0
  89. package/dist/esm/resolve-eval-files.js.map +1 -0
  90. package/dist/esm/utils/ab-error-message.js +34 -0
  91. package/dist/esm/utils/ab-error-message.js.map +1 -0
  92. package/dist/esm/utils/{agent-browser.js → ab.js} +3 -32
  93. package/dist/esm/utils/ab.js.map +1 -0
  94. package/dist/esm/utils/create-run-dir.js +24 -0
  95. package/dist/esm/utils/create-run-dir.js.map +1 -0
  96. package/dist/esm/utils/{process.js → helpers.js} +28 -11
  97. package/dist/esm/utils/helpers.js.map +1 -0
  98. package/dist/esm/utils/index.js +8 -5
  99. package/dist/esm/utils/index.js.map +1 -1
  100. package/dist/esm/utils/{browser-poll.js → poll-console.js} +5 -3
  101. package/dist/esm/utils/poll-console.js.map +1 -0
  102. package/dist/esm/utils/{daemon.js → reset-daemon.js} +5 -14
  103. package/dist/esm/utils/reset-daemon.js.map +1 -0
  104. package/dist/esm/utils/resolve-app-key.js +20 -0
  105. package/dist/esm/utils/resolve-app-key.js.map +1 -0
  106. package/dist/esm/utils/wait-for-server.js +26 -0
  107. package/dist/esm/utils/wait-for-server.js.map +1 -0
  108. package/dist/esm/version.js +1 -1
  109. package/dist/tsconfig.tsbuildinfo +1 -1
  110. package/dist/types/commands/app/format-plan.d.ts +8 -0
  111. package/dist/types/commands/app/format-step-result.d.ts +8 -0
  112. package/dist/types/commands/app/format-verdict.d.ts +8 -0
  113. package/dist/types/commands/app/prompts/{step.prompt.d.ts → create-step-prompt.d.ts} +1 -1
  114. package/dist/types/commands/app/status-icon.d.ts +8 -0
  115. package/dist/types/commands/app/tools/create-append-file-tool.d.ts +10 -0
  116. package/dist/types/commands/app/tools/{write-file.d.ts → create-write-file-tool.d.ts} +0 -9
  117. package/dist/types/commands/app/truncate.d.ts +8 -0
  118. package/dist/types/commands/app/try-format-message.d.ts +10 -0
  119. package/dist/types/exit-with-resolution-error.d.ts +8 -0
  120. package/dist/types/{eval-resolve.d.ts → resolve-eval-command-input.d.ts} +0 -8
  121. package/dist/types/resolve-eval-files.d.ts +8 -0
  122. package/dist/types/utils/ab-error-message.d.ts +11 -0
  123. package/dist/types/utils/{agent-browser.d.ts → ab.d.ts} +0 -13
  124. package/dist/types/utils/create-run-dir.d.ts +8 -0
  125. package/dist/types/utils/{process.d.ts → helpers.d.ts} +13 -6
  126. package/dist/types/utils/index.d.ts +8 -5
  127. package/dist/types/utils/{daemon.d.ts → reset-daemon.d.ts} +0 -5
  128. package/dist/types/utils/resolve-app-key.d.ts +9 -0
  129. package/dist/types/utils/wait-for-server.d.ts +9 -0
  130. package/dist/types/version.d.ts +1 -1
  131. package/package.json +4 -4
  132. package/src/commands/app/{session-logger.ts → attach-session-logger.ts} +15 -1
  133. package/src/commands/app/{command.ts → copilot-command.ts} +21 -12
  134. package/src/commands/app/{eval.ts → create-session.ts} +6 -4
  135. package/src/commands/app/format-plan.ts +26 -0
  136. package/src/commands/app/format-step-result.ts +16 -0
  137. package/src/commands/app/format-verdict.ts +43 -0
  138. package/src/commands/app/prompts/{judge.prompt.ts → create-judge-prompt.ts} +4 -0
  139. package/src/commands/app/prompts/{step.prompt.ts → create-step-prompt.ts} +2 -1
  140. package/src/commands/app/{login.ts → run-login.ts} +4 -0
  141. package/src/commands/app/{server.ts → start-app-server.ts} +6 -0
  142. package/src/commands/app/status-icon.ts +16 -0
  143. package/src/commands/app/tools/{write-file.ts → create-append-file-tool.ts} +4 -39
  144. package/src/commands/app/tools/{find.ts → create-find-tool.ts} +3 -0
  145. package/src/commands/app/tools/{read-file.ts → create-read-file-tool.ts} +3 -1
  146. package/src/commands/app/tools/{screenshot.ts → create-screenshot-tool.ts} +6 -0
  147. package/src/commands/app/tools/{scroll.ts → create-scroll-tool.ts} +2 -0
  148. package/src/commands/app/tools/{wait.ts → create-wait-tool.ts} +4 -0
  149. package/src/commands/app/tools/create-write-file-tool.ts +69 -0
  150. package/src/commands/app/tools/index.ts +19 -19
  151. package/src/commands/app/truncate.ts +10 -0
  152. package/src/commands/app/try-format-message.ts +42 -0
  153. package/src/exit-with-resolution-error.ts +15 -0
  154. package/src/index.ts +1 -1
  155. package/src/resolve-eval-command-input.ts +59 -0
  156. package/src/resolve-eval-files.ts +57 -0
  157. package/src/utils/ab-error-message.ts +31 -0
  158. package/src/utils/{agent-browser.ts → ab.ts} +2 -30
  159. package/src/utils/create-run-dir.ts +24 -0
  160. package/src/utils/{process.ts → helpers.ts} +28 -10
  161. package/src/utils/index.ts +8 -5
  162. package/src/utils/{browser-poll.ts → poll-console.ts} +4 -2
  163. package/src/utils/{daemon.ts → reset-daemon.ts} +4 -13
  164. package/src/utils/resolve-app-key.ts +20 -0
  165. package/src/utils/wait-for-server.ts +24 -0
  166. package/src/version.ts +1 -1
  167. package/dist/esm/commands/app/command.js.map +0 -1
  168. package/dist/esm/commands/app/eval.js.map +0 -1
  169. package/dist/esm/commands/app/format.js +0 -93
  170. package/dist/esm/commands/app/format.js.map +0 -1
  171. package/dist/esm/commands/app/login.js.map +0 -1
  172. package/dist/esm/commands/app/prompts/execute-step.prompt.js.map +0 -1
  173. package/dist/esm/commands/app/prompts/judge.prompt.js.map +0 -1
  174. package/dist/esm/commands/app/prompts/plan.prompt.js.map +0 -1
  175. package/dist/esm/commands/app/prompts/step.prompt.js.map +0 -1
  176. package/dist/esm/commands/app/prompts/system.dev-server.prompt.js.map +0 -1
  177. package/dist/esm/commands/app/prompts/system.prompt.js.map +0 -1
  178. package/dist/esm/commands/app/server.js.map +0 -1
  179. package/dist/esm/commands/app/session-logger.js.map +0 -1
  180. package/dist/esm/commands/app/tools/click.js.map +0 -1
  181. package/dist/esm/commands/app/tools/errors.js.map +0 -1
  182. package/dist/esm/commands/app/tools/eval-js.js.map +0 -1
  183. package/dist/esm/commands/app/tools/fill.js.map +0 -1
  184. package/dist/esm/commands/app/tools/find.js.map +0 -1
  185. package/dist/esm/commands/app/tools/get-styles.js.map +0 -1
  186. package/dist/esm/commands/app/tools/get-url.js.map +0 -1
  187. package/dist/esm/commands/app/tools/go-back.js.map +0 -1
  188. package/dist/esm/commands/app/tools/hover.js.map +0 -1
  189. package/dist/esm/commands/app/tools/navigate.js.map +0 -1
  190. package/dist/esm/commands/app/tools/press-key.js.map +0 -1
  191. package/dist/esm/commands/app/tools/read-file.js.map +0 -1
  192. package/dist/esm/commands/app/tools/registry.js.map +0 -1
  193. package/dist/esm/commands/app/tools/reload.js.map +0 -1
  194. package/dist/esm/commands/app/tools/screenshot.js.map +0 -1
  195. package/dist/esm/commands/app/tools/scroll.js.map +0 -1
  196. package/dist/esm/commands/app/tools/select.js.map +0 -1
  197. package/dist/esm/commands/app/tools/snapshot.js.map +0 -1
  198. package/dist/esm/commands/app/tools/type-text.js.map +0 -1
  199. package/dist/esm/commands/app/tools/wait.js.map +0 -1
  200. package/dist/esm/commands/app/tools/write-file.js.map +0 -1
  201. package/dist/esm/eval-resolve.js +0 -83
  202. package/dist/esm/eval-resolve.js.map +0 -1
  203. package/dist/esm/utils/agent-browser.js.map +0 -1
  204. package/dist/esm/utils/browser-poll.js.map +0 -1
  205. package/dist/esm/utils/daemon.js.map +0 -1
  206. package/dist/esm/utils/process.js.map +0 -1
  207. package/dist/esm/utils/server.js +0 -65
  208. package/dist/esm/utils/server.js.map +0 -1
  209. package/dist/types/commands/app/format.d.ts +0 -14
  210. package/dist/types/utils/server.d.ts +0 -26
  211. package/src/commands/app/format.ts +0 -110
  212. package/src/eval-resolve.ts +0 -113
  213. package/src/utils/server.ts +0 -66
  214. /package/dist/types/commands/app/{session-logger.d.ts → attach-session-logger.d.ts} +0 -0
  215. /package/dist/types/commands/app/{command.d.ts → copilot-command.d.ts} +0 -0
  216. /package/dist/types/commands/app/{eval.d.ts → create-session.d.ts} +0 -0
  217. /package/dist/types/commands/app/prompts/{system.dev-server.prompt.d.ts → create-dev-server-context.d.ts} +0 -0
  218. /package/dist/types/commands/app/prompts/{execute-step.prompt.d.ts → create-execute-step-prompt.d.ts} +0 -0
  219. /package/dist/types/commands/app/prompts/{judge.prompt.d.ts → create-judge-prompt.d.ts} +0 -0
  220. /package/dist/types/commands/app/prompts/{plan.prompt.d.ts → create-plan-prompt.d.ts} +0 -0
  221. /package/dist/types/commands/app/prompts/{system.prompt.d.ts → create-system-prompt.d.ts} +0 -0
  222. /package/dist/types/commands/app/{login.d.ts → run-login.d.ts} +0 -0
  223. /package/dist/types/commands/app/{server.d.ts → start-app-server.d.ts} +0 -0
  224. /package/dist/types/commands/app/tools/{registry.d.ts → AgentBrowserToolRegistry.d.ts} +0 -0
  225. /package/dist/types/commands/app/tools/{click.d.ts → create-click-tool.d.ts} +0 -0
  226. /package/dist/types/commands/app/tools/{errors.d.ts → create-errors-tool.d.ts} +0 -0
  227. /package/dist/types/commands/app/tools/{eval-js.d.ts → create-eval-js-tool.d.ts} +0 -0
  228. /package/dist/types/commands/app/tools/{fill.d.ts → create-fill-tool.d.ts} +0 -0
  229. /package/dist/types/commands/app/tools/{find.d.ts → create-find-tool.d.ts} +0 -0
  230. /package/dist/types/commands/app/tools/{get-styles.d.ts → create-get-styles-tool.d.ts} +0 -0
  231. /package/dist/types/commands/app/tools/{get-url.d.ts → create-get-url-tool.d.ts} +0 -0
  232. /package/dist/types/commands/app/tools/{go-back.d.ts → create-go-back-tool.d.ts} +0 -0
  233. /package/dist/types/commands/app/tools/{hover.d.ts → create-hover-tool.d.ts} +0 -0
  234. /package/dist/types/commands/app/tools/{navigate.d.ts → create-navigate-tool.d.ts} +0 -0
  235. /package/dist/types/commands/app/tools/{press-key.d.ts → create-press-key-tool.d.ts} +0 -0
  236. /package/dist/types/commands/app/tools/{read-file.d.ts → create-read-file-tool.d.ts} +0 -0
  237. /package/dist/types/commands/app/tools/{reload.d.ts → create-reload-tool.d.ts} +0 -0
  238. /package/dist/types/commands/app/tools/{screenshot.d.ts → create-screenshot-tool.d.ts} +0 -0
  239. /package/dist/types/commands/app/tools/{scroll.d.ts → create-scroll-tool.d.ts} +0 -0
  240. /package/dist/types/commands/app/tools/{select.d.ts → create-select-tool.d.ts} +0 -0
  241. /package/dist/types/commands/app/tools/{snapshot.d.ts → create-snapshot-tool.d.ts} +0 -0
  242. /package/dist/types/commands/app/tools/{type-text.d.ts → create-type-text-tool.d.ts} +0 -0
  243. /package/dist/types/commands/app/tools/{wait.d.ts → create-wait-tool.d.ts} +0 -0
  244. /package/dist/types/utils/{browser-poll.d.ts → poll-console.d.ts} +0 -0
  245. /package/src/commands/app/prompts/{system.dev-server.prompt.ts → create-dev-server-context.ts} +0 -0
  246. /package/src/commands/app/prompts/{execute-step.prompt.ts → create-execute-step-prompt.ts} +0 -0
  247. /package/src/commands/app/prompts/{plan.prompt.ts → create-plan-prompt.ts} +0 -0
  248. /package/src/commands/app/prompts/{system.prompt.ts → create-system-prompt.ts} +0 -0
  249. /package/src/commands/app/tools/{registry.ts → AgentBrowserToolRegistry.ts} +0 -0
  250. /package/src/commands/app/tools/{click.ts → create-click-tool.ts} +0 -0
  251. /package/src/commands/app/tools/{errors.ts → create-errors-tool.ts} +0 -0
  252. /package/src/commands/app/tools/{eval-js.ts → create-eval-js-tool.ts} +0 -0
  253. /package/src/commands/app/tools/{fill.ts → create-fill-tool.ts} +0 -0
  254. /package/src/commands/app/tools/{get-styles.ts → create-get-styles-tool.ts} +0 -0
  255. /package/src/commands/app/tools/{get-url.ts → create-get-url-tool.ts} +0 -0
  256. /package/src/commands/app/tools/{go-back.ts → create-go-back-tool.ts} +0 -0
  257. /package/src/commands/app/tools/{hover.ts → create-hover-tool.ts} +0 -0
  258. /package/src/commands/app/tools/{navigate.ts → create-navigate-tool.ts} +0 -0
  259. /package/src/commands/app/tools/{press-key.ts → create-press-key-tool.ts} +0 -0
  260. /package/src/commands/app/tools/{reload.ts → create-reload-tool.ts} +0 -0
  261. /package/src/commands/app/tools/{select.ts → create-select-tool.ts} +0 -0
  262. /package/src/commands/app/tools/{snapshot.ts → create-snapshot-tool.ts} +0 -0
  263. /package/src/commands/app/tools/{type-text.ts → create-type-text-tool.ts} +0 -0
@@ -0,0 +1,8 @@
1
+ import type { Plan } from './types.js';
2
+ /**
3
+ * Renders a structured plan as a human-readable summary.
4
+ *
5
+ * @param plan - The plan to render, containing a summary and ordered steps.
6
+ * @returns A multi-line string suitable for console output.
7
+ */
8
+ export declare function formatPlan(plan: Plan): string;
@@ -0,0 +1,8 @@
1
+ import type { StepResult } from './types.js';
2
+ /**
3
+ * Renders a single step execution result.
4
+ *
5
+ * @param result - The step result to render, including its outcome, note, and evidence.
6
+ * @returns A formatted two-line string describing the step outcome.
7
+ */
8
+ export declare function formatStepResult(result: StepResult): string;
@@ -0,0 +1,8 @@
1
+ import type { Verdict } from './types.js';
2
+ /**
3
+ * Renders the final verdict as a full-width coloured report.
4
+ *
5
+ * @param verdict - The verdict to render, including per-step results, reasoning, and UX feedback.
6
+ * @returns A multi-line string suitable for console output.
7
+ */
8
+ export declare function formatVerdict(verdict: Verdict): string;
@@ -9,4 +9,4 @@ import type { PlanStep, RuntimeExecutionContext } from '../types.js';
9
9
  * @param ctx - Runtime context with output directory and app URL
10
10
  * @returns The fully interpolated prompt string
11
11
  */
12
- export declare const createStepPrompt: (step: PlanStep, ctx: RuntimeExecutionContext) => string;
12
+ export declare const createStepPrompt: (step: PlanStep, _ctx: RuntimeExecutionContext) => string;
@@ -0,0 +1,8 @@
1
+ /**
2
+ * Renders a status glyph for a step or verdict outcome.
3
+ *
4
+ * @param ok - Outcome value: `true` (pass), `false` (fail), or a string label
5
+ * such as `'blocked'` or `'flaky'` for anything in between.
6
+ * @returns A single coloured glyph representing the outcome.
7
+ */
8
+ export declare function statusIcon(ok: boolean | string): string;
@@ -0,0 +1,10 @@
1
+ import type { DefineTool } from './types.js';
2
+ /**
3
+ * Creates the append-file tool so the agent can append lines
4
+ * to artifacts like executions.jsonl.
5
+ *
6
+ * @param baseDir - The run output directory that scopes all writes
7
+ * @param defineTool - Copilot SDK helper used to declare tools
8
+ * @returns Copilot tool definition for appending to a file
9
+ */
10
+ export declare function createAppendFileTool(baseDir: string, defineTool: DefineTool): import("node_modules/@github/copilot-sdk/dist/types.js").Tool<unknown>;
@@ -8,12 +8,3 @@ import type { DefineTool } from './types.js';
8
8
  * @returns Copilot tool definition for writing a file
9
9
  */
10
10
  export declare function createWriteFileTool(baseDir: string, defineTool: DefineTool): import("node_modules/@github/copilot-sdk/dist/types.js").Tool<unknown>;
11
- /**
12
- * Creates the append-file tool so the agent can append lines
13
- * to artifacts like executions.jsonl.
14
- *
15
- * @param baseDir - The run output directory that scopes all writes
16
- * @param defineTool - Copilot SDK helper used to declare tools
17
- * @returns Copilot tool definition for appending to a file
18
- */
19
- export declare function createAppendFileTool(baseDir: string, defineTool: DefineTool): import("node_modules/@github/copilot-sdk/dist/types.js").Tool<unknown>;
@@ -0,0 +1,8 @@
1
+ /**
2
+ * Truncates a string to a maximum length, appending an ellipsis when cut.
3
+ *
4
+ * @param str - The string to truncate.
5
+ * @param max - Maximum length of the returned string, including the ellipsis.
6
+ * @returns The original string, or a shortened version ending in `…`.
7
+ */
8
+ export declare function truncate(str: string, max: number): string;
@@ -0,0 +1,10 @@
1
+ /**
2
+ * Attempts to detect the JSON shape of an assistant message and format it.
3
+ *
4
+ * Returns `null` when the content is not a recognised structure, so the
5
+ * caller can fall back to plain-text rendering.
6
+ *
7
+ * @param content - Raw assistant message content, expected to be a JSON string.
8
+ * @returns A formatted string for a recognised plan, step result, or verdict, or `null` otherwise.
9
+ */
10
+ export declare function tryFormatMessage(content: string): string | null;
@@ -0,0 +1,8 @@
1
+ /**
2
+ * Prints a CLI resolution error and exits the current process.
3
+ *
4
+ * @param message - Primary error message.
5
+ * @param detail - Optional follow-up detail shown on the next line.
6
+ * @returns This function never returns because the process exits.
7
+ */
8
+ export declare function exitWithResolutionError(message: string, detail?: string): never;
@@ -21,11 +21,3 @@ export interface EvalCommandInput {
21
21
  * @returns Normalized application path and optional direct eval file path.
22
22
  */
23
23
  export declare function resolveEvalCommandInput(inputPath: string): EvalCommandInput;
24
- /**
25
- * Resolves eval markdown files for a Fusion application.
26
- *
27
- * @param appPath - Path to the Fusion application directory
28
- * @param evalOpt - Value of the `--eval` CLI option (name, path, or `undefined`)
29
- * @returns Array of absolute paths to eval markdown files
30
- */
31
- export declare function resolveEvalFiles(appPath: string, evalOpt?: string): string[];
@@ -0,0 +1,8 @@
1
+ /**
2
+ * Resolves eval markdown files for a Fusion application.
3
+ *
4
+ * @param appPath - Path to the Fusion application directory
5
+ * @param evalOpt - Value of the `--eval` CLI option (name, path, or `undefined`)
6
+ * @returns Array of absolute paths to eval markdown files
7
+ */
8
+ export declare function resolveEvalFiles(appPath: string, evalOpt?: string): string[];
@@ -0,0 +1,11 @@
1
+ /**
2
+ * Extracts the user-facing error message from an agent-browser failure.
3
+ *
4
+ * Strips ANSI escape codes from stderr and returns only the diagnostic
5
+ * lines prefixed with `✗` or `⚠`. Falls back to the first 200 characters
6
+ * of the error message when no diagnostic lines are found.
7
+ *
8
+ * @param err - The caught error (typically from {@link ab})
9
+ * @returns A single-line summary suitable for console output
10
+ */
11
+ export declare function abErrorMessage(err: unknown): string;
@@ -1,5 +1,3 @@
1
- /** Persistent Chrome profile directory used across agent-browser sessions. */
2
- export declare const PROFILE_DIR: string;
3
1
  /**
4
2
  * Runs an agent-browser command with the persistent Chrome profile.
5
3
  *
@@ -13,14 +11,3 @@ export declare const PROFILE_DIR: string;
13
11
  * @throws {Error} When `agent-browser` exits with a non-zero code or times out
14
12
  */
15
13
  export declare function ab(args: string[], timeoutMs?: number): string;
16
- /**
17
- * Extracts the user-facing error message from an agent-browser failure.
18
- *
19
- * Strips ANSI escape codes from stderr and returns only the diagnostic
20
- * lines prefixed with `✗` or `⚠`. Falls back to the first 200 characters
21
- * of the error message when no diagnostic lines are found.
22
- *
23
- * @param err - The caught error (typically from {@link ab})
24
- * @returns A single-line summary suitable for console output
25
- */
26
- export declare function abErrorMessage(err: unknown): string;
@@ -0,0 +1,8 @@
1
+ /**
2
+ * Creates a timestamped, run-specific output directory for eval artifacts.
3
+ *
4
+ * @param title - Human label used as the directory name prefix (slugified)
5
+ * @param baseDir - Optional parent directory override
6
+ * @returns Absolute path to the newly created directory
7
+ */
8
+ export declare function createRunDir(title: string, baseDir?: string): string;
@@ -1,10 +1,6 @@
1
1
  import type { ChildProcess } from 'node:child_process';
2
- /**
3
- * Sends `SIGTERM` to a child process if it is still running.
4
- *
5
- * @param proc - The child process to terminate (no-op when `undefined` or already killed)
6
- */
7
- export declare function cleanup(proc?: ChildProcess): void;
2
+ /** Persistent Chrome profile directory used across agent-browser sessions. */
3
+ export declare const PROFILE_DIR: string;
8
4
  /**
9
5
  * Returns a promise that resolves after the given delay.
10
6
  *
@@ -19,3 +15,14 @@ export declare function sleep(ms: number): Promise<void>;
19
15
  * @returns The input string with all ANSI escape sequences removed
20
16
  */
21
17
  export declare function stripAnsi(s: string): string;
18
+ /**
19
+ * Sends `SIGTERM` to a child process if it is still running.
20
+ *
21
+ * @param proc - The child process to terminate (no-op when `undefined` or already killed)
22
+ */
23
+ export declare function cleanup(proc?: ChildProcess): void;
24
+ /**
25
+ * Clears the MSAL `interaction.status` flag from `sessionStorage` in the
26
+ * running browser via `agent-browser eval`.
27
+ */
28
+ export declare function clearMsalInteraction(): void;
@@ -1,5 +1,8 @@
1
- export { ab, abErrorMessage, PROFILE_DIR } from './agent-browser.js';
2
- export { resetDaemon, clearMsalInteraction } from './daemon.js';
3
- export { cleanup, sleep, stripAnsi } from './process.js';
4
- export { createRunDir, resolveAppKey, waitForServer } from './server.js';
5
- export { pollConsole } from './browser-poll.js';
1
+ export { ab } from './ab.js';
2
+ export { abErrorMessage } from './ab-error-message.js';
3
+ export { PROFILE_DIR, sleep, stripAnsi, cleanup, clearMsalInteraction } from './helpers.js';
4
+ export { resetDaemon } from './reset-daemon.js';
5
+ export { createRunDir } from './create-run-dir.js';
6
+ export { resolveAppKey } from './resolve-app-key.js';
7
+ export { waitForServer } from './wait-for-server.js';
8
+ export { pollConsole } from './poll-console.js';
@@ -9,8 +9,3 @@
9
9
  * 4. Delete Session Storage to clear stuck MSAL `interaction.status` flags
10
10
  */
11
11
  export declare function resetDaemon(): void;
12
- /**
13
- * Clears the MSAL `interaction.status` flag from `sessionStorage` in the
14
- * running browser via `agent-browser eval`.
15
- */
16
- export declare function clearMsalInteraction(): void;
@@ -0,0 +1,9 @@
1
+ /**
2
+ * Resolves the Fusion `appKey` by running `ffc app manifest --silent`
3
+ * in the given application directory and parsing the JSON output.
4
+ *
5
+ * @param appDir - Absolute path to the Fusion application
6
+ * @returns The `appKey` string from the manifest
7
+ * @throws {Error} When `ffc app manifest` fails or returns invalid JSON
8
+ */
9
+ export declare function resolveAppKey(appDir: string): string;
@@ -0,0 +1,9 @@
1
+ /**
2
+ * Polls a server URL until it responds with a non-5xx status or the
3
+ * timeout is reached.
4
+ *
5
+ * @param url - The URL to poll (e.g. `http://localhost:3000`)
6
+ * @param timeoutSeconds - Maximum number of seconds to wait
7
+ * @returns `true` if the server responded before timeout, `false` otherwise
8
+ */
9
+ export declare function waitForServer(url: string, timeoutSeconds: number): Promise<boolean>;
@@ -1 +1 @@
1
- export declare const version = "2.0.2";
1
+ export declare const version = "2.0.3";
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@equinor/fusion-framework-cli-plugin-copilot",
3
- "version": "2.0.2",
3
+ "version": "2.0.3",
4
4
  "description": "Copilot SDK powered evaluation plugin for Fusion Framework CLI",
5
5
  "type": "module",
6
6
  "main": "dist/esm/index.js",
@@ -44,11 +44,11 @@
44
44
  "rxjs": "^7.8.2"
45
45
  },
46
46
  "peerDependencies": {
47
- "@equinor/fusion-framework-cli": "^15.1.1"
47
+ "@equinor/fusion-framework-cli": "^15.2.1"
48
48
  },
49
49
  "devDependencies": {
50
- "typescript": "^6.0.3",
51
- "@equinor/fusion-framework-cli": "^15.1.1"
50
+ "typescript": "^7.0.2",
51
+ "@equinor/fusion-framework-cli": "^15.2.1"
52
52
  },
53
53
  "scripts": {
54
54
  "build": "tsc -b",
@@ -3,7 +3,7 @@ import ora from 'ora';
3
3
 
4
4
  import type { CopilotSession } from '@github/copilot-sdk';
5
5
 
6
- import { tryFormatMessage } from './format.js';
6
+ import { tryFormatMessage } from './try-format-message.js';
7
7
 
8
8
  const TOOL_ICONS: Record<string, string> = {
9
9
  browser_screenshot: '📷',
@@ -31,7 +31,9 @@ export function attachSessionLogger(
31
31
  let spinner: ReturnType<typeof ora> | null = null;
32
32
 
33
33
  function syncSpinner(): void {
34
+ // No pending tools means the spinner has nothing left to show
34
35
  if (pendingTools.size === 0) {
36
+ // Stop the spinner only if one was actually running
35
37
  if (spinner) {
36
38
  spinner.stop();
37
39
  spinner = null;
@@ -39,6 +41,7 @@ export function attachSessionLogger(
39
41
  return;
40
42
  }
41
43
  const text = [...pendingTools.values()].join(chalk.dim(' | '));
44
+ // Reuse the existing spinner instance rather than starting a second one
42
45
  if (spinner) {
43
46
  spinner.text = text;
44
47
  } else {
@@ -47,6 +50,7 @@ export function attachSessionLogger(
47
50
  }
48
51
 
49
52
  function pauseSpinner(): void {
53
+ // Only stop the spinner if one is actually running
50
54
  if (spinner) {
51
55
  spinner.stop();
52
56
  spinner = null;
@@ -61,6 +65,7 @@ export function attachSessionLogger(
61
65
  }
62
66
 
63
67
  session.on((event) => {
68
+ // Dispatch on the Copilot SDK session event type to render the right log line
64
69
  switch (event.type) {
65
70
  case 'tool.execution_start': {
66
71
  const { toolCallId, toolName, arguments: args } = event.data;
@@ -74,6 +79,7 @@ export function attachSessionLogger(
74
79
  }
75
80
  case 'tool.execution_complete': {
76
81
  const label = pendingTools.get(event.data.toolCallId);
82
+ // Only log completion for tools we actually tracked the start of
77
83
  if (label) {
78
84
  pendingTools.delete(event.data.toolCallId);
79
85
  logCompletion(label, event.data.success);
@@ -82,6 +88,7 @@ export function attachSessionLogger(
82
88
  }
83
89
  case 'external_tool.completed': {
84
90
  const label = pendingTools.get(event.data.requestId);
91
+ // Only log completion for tools we actually tracked the start of
85
92
  if (label) {
86
93
  pendingTools.delete(event.data.requestId);
87
94
  logCompletion(label, true);
@@ -95,9 +102,11 @@ export function attachSessionLogger(
95
102
  break;
96
103
  }
97
104
  case 'assistant.message': {
105
+ // Skip empty assistant messages (e.g. tool-only turns)
98
106
  if (event.data.content) {
99
107
  pauseSpinner();
100
108
  const formatted = tryFormatMessage(event.data.content);
109
+ // Prefer the structured plan/verdict/step-result rendering when recognised
101
110
  if (formatted) {
102
111
  console.log(formatted);
103
112
  } else {
@@ -119,6 +128,7 @@ export function attachSessionLogger(
119
128
  }
120
129
  case 'permission.completed': {
121
130
  const label = pendingTools.get(event.data.requestId);
131
+ // Only log completion for permissions we actually tracked the request of
122
132
  if (label) {
123
133
  const approved = event.data.result?.kind === 'approved';
124
134
  pendingTools.delete(event.data.requestId);
@@ -128,8 +138,10 @@ export function attachSessionLogger(
128
138
  }
129
139
  case 'session.tools_updated': {
130
140
  const negotiatedModel = event.data.model as string | undefined;
141
+ // Only log tooling info once the server has actually negotiated a model
131
142
  if (negotiatedModel) {
132
143
  console.log(chalk.dim(`💾 ${negotiatedModel}`));
144
+ // Warn the user when the server picked a different model than requested
133
145
  if (options?.requestedModel && negotiatedModel !== options.requestedModel) {
134
146
  console.log(
135
147
  chalk.yellow(
@@ -157,6 +169,7 @@ export function attachSessionLogger(
157
169
  }
158
170
  case 'session.info': {
159
171
  const { message } = event.data as { message?: string };
172
+ // Skip empty info events
160
173
  if (message) {
161
174
  pauseSpinner();
162
175
  console.log(chalk.dim(`ℹ️ ${message}`));
@@ -166,6 +179,7 @@ export function attachSessionLogger(
166
179
  }
167
180
  case 'assistant.intent': {
168
181
  const { intent } = event.data as { intent?: string };
182
+ // Skip empty intent events
169
183
  if (intent) {
170
184
  pauseSpinner();
171
185
  console.log(chalk.yellow(`🎯 ${intent}`));
@@ -2,17 +2,18 @@ import { createCommand } from 'commander';
2
2
  import { basename } from 'node:path';
3
3
 
4
4
  import { resetDaemon, cleanup, createRunDir } from '../../utils/index.js';
5
- import { runLogin } from './login.js';
6
- import { resolveEvalCommandInput, resolveEvalFiles } from '../../eval-resolve.js';
7
- import { createSession } from './eval.js';
8
- import { startAppServer } from './server.js';
9
- import { attachSessionLogger } from './session-logger.js';
5
+ import { runLogin } from './run-login.js';
6
+ import { resolveEvalCommandInput } from '../../resolve-eval-command-input.js';
7
+ import { resolveEvalFiles } from '../../resolve-eval-files.js';
8
+ import { createSession } from './create-session.js';
9
+ import { startAppServer } from './start-app-server.js';
10
+ import { attachSessionLogger } from './attach-session-logger.js';
10
11
  import type { CopilotEvalOptions, Plan, Verdict } from './types.js';
11
- import { formatVerdict } from './format.js';
12
+ import { formatVerdict } from './format-verdict.js';
12
13
  import { existsSync, readFileSync } from 'node:fs';
13
- import { createPlanPrompt } from './prompts/plan.prompt.js';
14
- import { createStepPrompt } from './prompts/step.prompt.js';
15
- import { createJudgePrompt } from './prompts/judge.prompt.js';
14
+ import { createPlanPrompt } from './prompts/create-plan-prompt.js';
15
+ import { createStepPrompt } from './prompts/create-step-prompt.js';
16
+ import { createJudgePrompt } from './prompts/create-judge-prompt.js';
16
17
  import chalk from 'chalk';
17
18
 
18
19
  /**
@@ -58,6 +59,7 @@ const _appEvalCommand = createCommand('eval')
58
59
  const port = parseInt(options.port, 10);
59
60
  const verbose = options.verbose;
60
61
 
62
+ // Reject ambiguous input that selects an eval two different ways
61
63
  if (resolvedInput.evalFile && options.eval) {
62
64
  console.error('❌ Do not combine a positional eval markdown file with --eval');
63
65
  process.exit(1);
@@ -73,9 +75,9 @@ const _appEvalCommand = createCommand('eval')
73
75
  const evalFiles = resolvedInput.evalFile
74
76
  ? [resolvedInput.evalFile]
75
77
  : resolveEvalFiles(absAppPath, options.eval);
76
- console.log(
77
- `📋 Found ${evalFiles.length} eval(s): ${evalFiles.map((f) => basename(f)).join(', ')}`,
78
- );
78
+ // Summarize which eval files were discovered before the run starts
79
+ const evalFileNames = evalFiles.map((f) => basename(f)).join(', ');
80
+ console.log(`📋 Found ${evalFiles.length} eval(s): ${evalFileNames}`);
79
81
 
80
82
  // Start the app dev server (unless --url provides an already-running URL)
81
83
  const { serverProcess, appUrl } = await startAppServer(absAppPath, {
@@ -103,6 +105,7 @@ const _appEvalCommand = createCommand('eval')
103
105
 
104
106
  let failures = 0;
105
107
  try {
108
+ // Run every resolved eval file sequentially so output stays readable
106
109
  for (const evalFilePath of evalFiles) {
107
110
  const evalName = basename(evalFilePath, '.md');
108
111
  const query = readFileSync(evalFilePath, 'utf-8').trim();
@@ -129,6 +132,7 @@ const _appEvalCommand = createCommand('eval')
129
132
  await session.sendAndWait({ prompt: createPlanPrompt(query, ctx) }, 300_000);
130
133
 
131
134
  const planPath = `${runDir}/plan.json`;
135
+ // Bail out of this eval when the planning phase produced no plan file
132
136
  if (!existsSync(planPath)) {
133
137
  console.error(
134
138
  chalk.red(
@@ -138,6 +142,7 @@ const _appEvalCommand = createCommand('eval')
138
142
  session.disconnect();
139
143
  logger.stop();
140
144
  failures++;
145
+ // Skip execution/judging phases; this eval already failed at planning
141
146
  continue;
142
147
  }
143
148
 
@@ -147,6 +152,7 @@ const _appEvalCommand = createCommand('eval')
147
152
  // ── Phase 2: Execute + Evaluate each step ──────────────────
148
153
  for (const step of plan.steps) {
149
154
  console.log(chalk.cyan(`\n── Scenario: ${step.scenario}`));
155
+ // Print each acceptance criterion the agent will be judged against
150
156
  for (const c of step.criteria) {
151
157
  console.log(chalk.dim(` • ${c}`));
152
158
  }
@@ -162,9 +168,11 @@ const _appEvalCommand = createCommand('eval')
162
168
 
163
169
  // Print the verdict
164
170
  const verdictPath = `${runDir}/verdict.json`;
171
+ // Only report a verdict when the judge phase actually produced one
165
172
  if (existsSync(verdictPath)) {
166
173
  const verdict = JSON.parse(readFileSync(verdictPath, 'utf-8')) as Verdict;
167
174
  console.log(formatVerdict(verdict));
175
+ // A failing verdict counts toward the overall exit-code failure total
168
176
  if (!verdict.pass) failures++;
169
177
  } else {
170
178
  console.error(chalk.red(`❌ Judge did not produce ${verdictPath}.`));
@@ -174,6 +182,7 @@ const _appEvalCommand = createCommand('eval')
174
182
  logger?.stop();
175
183
  const msg = err instanceof Error ? err.message : String(err);
176
184
  console.error(chalk.red(`\n❌ Eval "${evalName}" failed: ${msg}`));
185
+ // Print the stack trace too when one is available for debugging
177
186
  if (err instanceof Error && err.stack) {
178
187
  console.error(chalk.dim(err.stack));
179
188
  }
@@ -3,12 +3,13 @@ import { join } from 'node:path';
3
3
 
4
4
  import { ab, abErrorMessage } from '../../utils/index.js';
5
5
  import { createAgentBrowserTools } from './tools/index.js';
6
- import { createWriteFileTool, createAppendFileTool } from './tools/write-file.js';
7
- import { createReadFileTool } from './tools/read-file.js';
6
+ import { createWriteFileTool } from './tools/create-write-file-tool.js';
7
+ import { createAppendFileTool } from './tools/create-append-file-tool.js';
8
+ import { createReadFileTool } from './tools/create-read-file-tool.js';
8
9
  import type { RuntimeExecutionContext } from './types.js';
9
10
  import type { CopilotSession, SessionConfig } from '@github/copilot-sdk';
10
- import { createSystemPrompt } from './prompts/system.prompt.js';
11
- import { createDevServerContext } from './prompts/system.dev-server.prompt.js';
11
+ import { createSystemPrompt } from './prompts/create-system-prompt.js';
12
+ import { createDevServerContext } from './prompts/create-dev-server-context.js';
12
13
 
13
14
  /**
14
15
  * Lazily imports the Copilot SDK to avoid module resolution errors at CLI startup.
@@ -44,6 +45,7 @@ export const createSession = async (options: SessionOptions): Promise<CopilotSes
44
45
  createAppendFileTool(ctx.outDir, defineTool),
45
46
  ];
46
47
 
48
+ // Combine built-in browser and file tools with any caller-supplied tools
47
49
  const tools = [
48
50
  ...createBrowserTools(defineTool, {
49
51
  cwd: ctx.outDir,
@@ -0,0 +1,26 @@
1
+ import chalk from 'chalk';
2
+
3
+ import type { Plan } from './types.js';
4
+ import { truncate } from './truncate.js';
5
+
6
+ /**
7
+ * Renders a structured plan as a human-readable summary.
8
+ *
9
+ * @param plan - The plan to render, containing a summary and ordered steps.
10
+ * @returns A multi-line string suitable for console output.
11
+ */
12
+ export function formatPlan(plan: Plan): string {
13
+ const lines = [
14
+ '',
15
+ chalk.bold(`📋 ${plan.summary}`),
16
+ '',
17
+ ...plan.steps.flatMap((s, si) => [
18
+ ` ${chalk.dim(`${si + 1}.`)} ${s.scenario}`,
19
+ ...s.criteria
20
+ // Truncate each criterion so long descriptions don't wrap the terminal
21
+ .map((c) => chalk.dim(` • ${truncate(c, 70)}`)),
22
+ ]),
23
+ '',
24
+ ];
25
+ return lines.join('\n');
26
+ }
@@ -0,0 +1,16 @@
1
+ import chalk from 'chalk';
2
+
3
+ import type { StepResult } from './types.js';
4
+ import { statusIcon } from './status-icon.js';
5
+
6
+ /**
7
+ * Renders a single step execution result.
8
+ *
9
+ * @param result - The step result to render, including its outcome, note, and evidence.
10
+ * @returns A formatted two-line string describing the step outcome.
11
+ */
12
+ export function formatStepResult(result: StepResult): string {
13
+ const icon = statusIcon(result.ok);
14
+ const files = result.evidence.length ? chalk.dim(` [${result.evidence.join(', ')}]`) : '';
15
+ return ` ${icon} ${result.criterion}\n${chalk.dim(` ${result.note}`)}${files}`;
16
+ }
@@ -0,0 +1,43 @@
1
+ import chalk from 'chalk';
2
+
3
+ import type { Verdict } from './types.js';
4
+ import { statusIcon } from './status-icon.js';
5
+
6
+ /**
7
+ * Renders the final verdict as a full-width coloured report.
8
+ *
9
+ * @param verdict - The verdict to render, including per-step results, reasoning, and UX feedback.
10
+ * @returns A multi-line string suitable for console output.
11
+ */
12
+ export function formatVerdict(verdict: Verdict): string {
13
+ const bar = '═'.repeat(60);
14
+ const banner = verdict.pass
15
+ ? chalk.bgGreen.black.bold(' ✅ PASS ')
16
+ : chalk.bgRed.white.bold(' ❌ FAIL ');
17
+
18
+ const lines = [
19
+ '',
20
+ bar,
21
+ ` ${banner}`,
22
+ bar,
23
+ '',
24
+ ...verdict.steps
25
+ // Render each step's outcome as a status glyph, criterion, and note
26
+ .map((s) => ` ${statusIcon(s.ok)} ${s.criterion}\n${chalk.dim(` ${s.note}`)}`),
27
+ '',
28
+ chalk.dim(` ${verdict.reasoning}`),
29
+ '',
30
+ ];
31
+
32
+ // Append optional UX feedback only when the judge actually provided any
33
+ if (verdict.ux && verdict.ux.length > 0) {
34
+ lines.push(chalk.bold(' 💡 UX Feedback'), '');
35
+ // List every UX hint as its own bullet line
36
+ for (const hint of verdict.ux) {
37
+ lines.push(chalk.yellow(` • ${hint}`));
38
+ }
39
+ lines.push('');
40
+ }
41
+
42
+ return lines.join('\n');
43
+ }
@@ -19,6 +19,7 @@ function collectEvidence(outDir: string): string {
19
19
 
20
20
  // ── executions.jsonl ──
21
21
  const execPath = join(outDir, 'executions.jsonl');
22
+ // Fall back to a placeholder note when the executions log is missing
22
23
  if (existsSync(execPath)) {
23
24
  parts.push('### executions.jsonl', readFileSync(execPath, 'utf-8').trim());
24
25
  } else {
@@ -27,10 +28,13 @@ function collectEvidence(outDir: string): string {
27
28
 
28
29
  // ── evidence/ directory ──
29
30
  const evidenceDir = join(outDir, 'evidence');
31
+ // Only scan for evidence files when the directory actually exists
30
32
  if (existsSync(evidenceDir)) {
31
33
  const files = readdirSync(evidenceDir).sort();
34
+ // Inline readable text evidence; list binary evidence by name only
32
35
  for (const file of files) {
33
36
  const ext = extname(file).toLowerCase();
37
+ // Inline the content of readable text extensions; list other files by name only
34
38
  if (TEXT_EXTENSIONS.has(ext)) {
35
39
  const content = readFileSync(join(evidenceDir, file), 'utf-8').trim();
36
40
  parts.push(`### evidence/${file}`, content);
@@ -10,8 +10,9 @@ import type { PlanStep, RuntimeExecutionContext } from '../types.js';
10
10
  * @param ctx - Runtime context with output directory and app URL
11
11
  * @returns The fully interpolated prompt string
12
12
  */
13
- export const createStepPrompt = (step: PlanStep, ctx: RuntimeExecutionContext): string => {
13
+ export const createStepPrompt = (step: PlanStep, _ctx: RuntimeExecutionContext): string => {
14
14
  const slug = slugify(step.scenario);
15
+ // Render each criterion with its expected pass/fail evidence for the prompt
15
16
  const criteriaBlock = step.criteria
16
17
  .map((c, i) => `${i + 1}. ${c}\n Pass: ${step.pass[i] ?? ''}\n Fail: ${step.fail[i] ?? ''}`)
17
18
  .join('\n');