@shepai/cli 1.121.0 → 1.122.0-pr392.ff1c944

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 (275) hide show
  1. package/apis/json-schema/PhaseTiming.yaml +17 -0
  2. package/dist/packages/core/src/application/ports/output/agents/agent-executor.interface.d.ts +19 -5
  3. package/dist/packages/core/src/application/ports/output/agents/agent-executor.interface.d.ts.map +1 -1
  4. package/dist/packages/core/src/application/ports/output/agents/phase-timing-repository.interface.d.ts +1 -1
  5. package/dist/packages/core/src/application/ports/output/agents/phase-timing-repository.interface.d.ts.map +1 -1
  6. package/dist/packages/core/src/application/use-cases/features/resume-feature.use-case.d.ts +3 -1
  7. package/dist/packages/core/src/application/use-cases/features/resume-feature.use-case.d.ts.map +1 -1
  8. package/dist/packages/core/src/application/use-cases/features/resume-feature.use-case.js +4 -2
  9. package/dist/packages/core/src/domain/generated/output.d.ts +22 -0
  10. package/dist/packages/core/src/domain/generated/output.d.ts.map +1 -1
  11. package/dist/packages/core/src/infrastructure/persistence/sqlite/migrations/039-add-phase-timing-extended-stats.d.ts +11 -0
  12. package/dist/packages/core/src/infrastructure/persistence/sqlite/migrations/039-add-phase-timing-extended-stats.d.ts.map +1 -0
  13. package/dist/packages/core/src/infrastructure/persistence/sqlite/migrations/039-add-phase-timing-extended-stats.js +25 -0
  14. package/dist/packages/core/src/infrastructure/repositories/sqlite-phase-timing.repository.d.ts +1 -1
  15. package/dist/packages/core/src/infrastructure/repositories/sqlite-phase-timing.repository.d.ts.map +1 -1
  16. package/dist/packages/core/src/infrastructure/repositories/sqlite-phase-timing.repository.js +42 -2
  17. package/dist/packages/core/src/infrastructure/services/agents/common/executors/claude-code-executor.service.d.ts +5 -0
  18. package/dist/packages/core/src/infrastructure/services/agents/common/executors/claude-code-executor.service.d.ts.map +1 -1
  19. package/dist/packages/core/src/infrastructure/services/agents/common/executors/claude-code-executor.service.js +38 -13
  20. package/dist/packages/core/src/infrastructure/services/agents/common/executors/dev-executor.service.d.ts.map +1 -1
  21. package/dist/packages/core/src/infrastructure/services/agents/common/executors/dev-executor.service.js +23 -2
  22. package/dist/packages/core/src/infrastructure/services/agents/feature-agent/nodes/evidence-output-parser.d.ts +21 -0
  23. package/dist/packages/core/src/infrastructure/services/agents/feature-agent/nodes/evidence-output-parser.d.ts.map +1 -1
  24. package/dist/packages/core/src/infrastructure/services/agents/feature-agent/nodes/evidence-output-parser.js +71 -0
  25. package/dist/packages/core/src/infrastructure/services/agents/feature-agent/nodes/evidence.node.d.ts.map +1 -1
  26. package/dist/packages/core/src/infrastructure/services/agents/feature-agent/nodes/evidence.node.js +11 -1
  27. package/dist/packages/core/src/infrastructure/services/agents/feature-agent/nodes/fast-implement.node.d.ts.map +1 -1
  28. package/dist/packages/core/src/infrastructure/services/agents/feature-agent/nodes/fast-implement.node.js +34 -1
  29. package/dist/packages/core/src/infrastructure/services/agents/feature-agent/nodes/merge/merge.node.d.ts.map +1 -1
  30. package/dist/packages/core/src/infrastructure/services/agents/feature-agent/nodes/merge/merge.node.js +12 -0
  31. package/dist/packages/core/src/infrastructure/services/agents/feature-agent/nodes/node-helpers.d.ts.map +1 -1
  32. package/dist/packages/core/src/infrastructure/services/agents/feature-agent/nodes/node-helpers.js +5 -0
  33. package/dist/packages/core/src/infrastructure/services/agents/feature-agent/nodes/prompts/evidence-prompts.d.ts.map +1 -1
  34. package/dist/packages/core/src/infrastructure/services/agents/feature-agent/nodes/prompts/evidence-prompts.js +18 -6
  35. package/dist/packages/core/src/infrastructure/services/agents/feature-agent/nodes/prompts/fast-implement.prompt.d.ts.map +1 -1
  36. package/dist/packages/core/src/infrastructure/services/agents/feature-agent/nodes/prompts/fast-implement.prompt.js +4 -1
  37. package/dist/packages/core/src/infrastructure/services/agents/feature-agent/phase-timing-context.d.ts +5 -0
  38. package/dist/packages/core/src/infrastructure/services/agents/feature-agent/phase-timing-context.d.ts.map +1 -1
  39. package/dist/packages/core/src/infrastructure/services/agents/feature-agent/phase-timing-context.js +9 -0
  40. package/dist/packages/core/src/infrastructure/services/git/git-pr.service.d.ts +1 -0
  41. package/dist/packages/core/src/infrastructure/services/git/git-pr.service.d.ts.map +1 -1
  42. package/dist/packages/core/src/infrastructure/services/git/git-pr.service.js +20 -1
  43. package/dist/src/presentation/tui/prompts/prd-review-question.prompt.d.ts +1 -1
  44. package/dist/src/presentation/tui/prompts/prd-review-question.prompt.d.ts.map +1 -1
  45. package/dist/src/presentation/tui/prompts/prd-review-question.prompt.js +5 -2
  46. package/dist/src/presentation/tui/wizards/prd-review.wizard.d.ts.map +1 -1
  47. package/dist/src/presentation/tui/wizards/prd-review.wizard.js +4 -2
  48. package/dist/src/presentation/web/app/(dashboard)/get-graph-data.d.ts.map +1 -1
  49. package/dist/src/presentation/web/app/(dashboard)/get-graph-data.js +2 -43
  50. package/dist/src/presentation/web/app/actions/approve-feature.d.ts.map +1 -1
  51. package/dist/src/presentation/web/app/actions/approve-feature.js +9 -0
  52. package/dist/src/presentation/web/app/actions/get-feature-phase-timings.d.ts +5 -0
  53. package/dist/src/presentation/web/app/actions/get-feature-phase-timings.d.ts.map +1 -1
  54. package/dist/src/presentation/web/app/actions/get-feature-phase-timings.js +5 -0
  55. package/dist/src/presentation/web/app/actions/reject-feature.d.ts.map +1 -1
  56. package/dist/src/presentation/web/app/actions/reject-feature.js +9 -0
  57. package/dist/src/presentation/web/app/actions/stop-feature.d.ts +5 -0
  58. package/dist/src/presentation/web/app/actions/stop-feature.d.ts.map +1 -0
  59. package/dist/src/presentation/web/app/actions/stop-feature.js +30 -0
  60. package/dist/src/presentation/web/app/api/npm-version/route.d.ts.map +1 -1
  61. package/dist/src/presentation/web/app/api/npm-version/route.js +9 -1
  62. package/dist/src/presentation/web/app/api/sessions/route.d.ts.map +1 -1
  63. package/dist/src/presentation/web/app/api/sessions/route.js +43 -10
  64. package/dist/src/presentation/web/components/common/feature-drawer-tabs/activity-tab.d.ts.map +1 -1
  65. package/dist/src/presentation/web/components/common/feature-drawer-tabs/activity-tab.js +104 -28
  66. package/dist/src/presentation/web/components/common/feature-drawer-tabs/activity-tab.stories.d.ts.map +1 -1
  67. package/dist/src/presentation/web/components/common/feature-drawer-tabs/activity-tab.stories.js +35 -0
  68. package/dist/src/presentation/web/components/common/feature-drawer-tabs/overview-tab.d.ts.map +1 -1
  69. package/dist/src/presentation/web/components/common/feature-drawer-tabs/overview-tab.js +2 -2
  70. package/dist/src/presentation/web/components/common/feature-drawer-tabs/overview-tab.stories.d.ts +2 -0
  71. package/dist/src/presentation/web/components/common/feature-drawer-tabs/overview-tab.stories.d.ts.map +1 -1
  72. package/dist/src/presentation/web/components/common/feature-drawer-tabs/overview-tab.stories.js +4 -0
  73. package/dist/src/presentation/web/components/common/feature-node/feature-node-state-config.d.ts +1 -0
  74. package/dist/src/presentation/web/components/common/feature-node/feature-node-state-config.d.ts.map +1 -1
  75. package/dist/src/presentation/web/components/common/prd-questionnaire/prd-questionnaire.js +1 -1
  76. package/dist/src/presentation/web/components/features/control-center/control-center-inner.d.ts.map +1 -1
  77. package/dist/src/presentation/web/components/features/control-center/control-center-inner.js +3 -1
  78. package/dist/src/presentation/web/components/features/control-center/use-control-center-state.d.ts +1 -0
  79. package/dist/src/presentation/web/components/features/control-center/use-control-center-state.d.ts.map +1 -1
  80. package/dist/src/presentation/web/components/features/control-center/use-control-center-state.js +18 -0
  81. package/dist/src/presentation/web/lib/derive-graph.d.ts +2 -0
  82. package/dist/src/presentation/web/lib/derive-graph.d.ts.map +1 -1
  83. package/dist/src/presentation/web/lib/derive-graph.js +5 -0
  84. package/dist/tsconfig.build.tsbuildinfo +1 -1
  85. package/package.json +3 -5
  86. package/web/.next/BUILD_ID +1 -1
  87. package/web/.next/build-manifest.json +2 -2
  88. package/web/.next/fallback-build-manifest.json +2 -2
  89. package/web/.next/prerender-manifest.json +3 -3
  90. package/web/.next/required-server-files.js +3 -3
  91. package/web/.next/required-server-files.json +3 -3
  92. package/web/.next/server/app/(dashboard)/@drawer/create/page/server-reference-manifest.json +57 -42
  93. package/web/.next/server/app/(dashboard)/@drawer/create/page.js +1 -1
  94. package/web/.next/server/app/(dashboard)/@drawer/create/page.js.nft.json +1 -1
  95. package/web/.next/server/app/(dashboard)/@drawer/create/page_client-reference-manifest.js +1 -1
  96. package/web/.next/server/app/(dashboard)/@drawer/feature/[featureId]/[tab]/page/server-reference-manifest.json +69 -54
  97. package/web/.next/server/app/(dashboard)/@drawer/feature/[featureId]/[tab]/page.js +1 -1
  98. package/web/.next/server/app/(dashboard)/@drawer/feature/[featureId]/[tab]/page.js.nft.json +1 -1
  99. package/web/.next/server/app/(dashboard)/@drawer/feature/[featureId]/[tab]/page_client-reference-manifest.js +1 -1
  100. package/web/.next/server/app/(dashboard)/@drawer/feature/[featureId]/page/server-reference-manifest.json +69 -54
  101. package/web/.next/server/app/(dashboard)/@drawer/feature/[featureId]/page.js +1 -1
  102. package/web/.next/server/app/(dashboard)/@drawer/feature/[featureId]/page.js.nft.json +1 -1
  103. package/web/.next/server/app/(dashboard)/@drawer/feature/[featureId]/page_client-reference-manifest.js +1 -1
  104. package/web/.next/server/app/(dashboard)/@drawer/repository/[repositoryId]/page/server-reference-manifest.json +53 -38
  105. package/web/.next/server/app/(dashboard)/@drawer/repository/[repositoryId]/page.js +1 -1
  106. package/web/.next/server/app/(dashboard)/@drawer/repository/[repositoryId]/page.js.nft.json +1 -1
  107. package/web/.next/server/app/(dashboard)/@drawer/repository/[repositoryId]/page_client-reference-manifest.js +1 -1
  108. package/web/.next/server/app/(dashboard)/create/page/server-reference-manifest.json +57 -42
  109. package/web/.next/server/app/(dashboard)/create/page.js +1 -1
  110. package/web/.next/server/app/(dashboard)/create/page.js.nft.json +1 -1
  111. package/web/.next/server/app/(dashboard)/create/page_client-reference-manifest.js +1 -1
  112. package/web/.next/server/app/(dashboard)/feature/[featureId]/[tab]/page/server-reference-manifest.json +69 -54
  113. package/web/.next/server/app/(dashboard)/feature/[featureId]/[tab]/page.js +1 -1
  114. package/web/.next/server/app/(dashboard)/feature/[featureId]/[tab]/page.js.nft.json +1 -1
  115. package/web/.next/server/app/(dashboard)/feature/[featureId]/[tab]/page_client-reference-manifest.js +1 -1
  116. package/web/.next/server/app/(dashboard)/feature/[featureId]/page/server-reference-manifest.json +69 -54
  117. package/web/.next/server/app/(dashboard)/feature/[featureId]/page.js +1 -1
  118. package/web/.next/server/app/(dashboard)/feature/[featureId]/page.js.nft.json +1 -1
  119. package/web/.next/server/app/(dashboard)/feature/[featureId]/page_client-reference-manifest.js +1 -1
  120. package/web/.next/server/app/(dashboard)/page/server-reference-manifest.json +53 -38
  121. package/web/.next/server/app/(dashboard)/page.js +1 -1
  122. package/web/.next/server/app/(dashboard)/page.js.nft.json +1 -1
  123. package/web/.next/server/app/(dashboard)/page_client-reference-manifest.js +1 -1
  124. package/web/.next/server/app/(dashboard)/repository/[repositoryId]/page/server-reference-manifest.json +53 -38
  125. package/web/.next/server/app/(dashboard)/repository/[repositoryId]/page.js +1 -1
  126. package/web/.next/server/app/(dashboard)/repository/[repositoryId]/page.js.nft.json +1 -1
  127. package/web/.next/server/app/(dashboard)/repository/[repositoryId]/page_client-reference-manifest.js +1 -1
  128. package/web/.next/server/app/_global-error.html +2 -2
  129. package/web/.next/server/app/_global-error.rsc +1 -1
  130. package/web/.next/server/app/_global-error.segments/__PAGE__.segment.rsc +1 -1
  131. package/web/.next/server/app/_global-error.segments/_full.segment.rsc +1 -1
  132. package/web/.next/server/app/_global-error.segments/_head.segment.rsc +1 -1
  133. package/web/.next/server/app/_global-error.segments/_index.segment.rsc +1 -1
  134. package/web/.next/server/app/_global-error.segments/_tree.segment.rsc +1 -1
  135. package/web/.next/server/app/_not-found/page/server-reference-manifest.json +1 -1
  136. package/web/.next/server/app/_not-found/page_client-reference-manifest.js +1 -1
  137. package/web/.next/server/app/api/attachments/preview/route.js.nft.json +1 -1
  138. package/web/.next/server/app/api/evidence/route.js.nft.json +1 -1
  139. package/web/.next/server/app/api/graph-data/route.js.nft.json +1 -1
  140. package/web/.next/server/app/api/sessions/route.js +1 -1
  141. package/web/.next/server/app/api/sessions/route.js.nft.json +1 -1
  142. package/web/.next/server/app/settings/page/server-reference-manifest.json +6 -6
  143. package/web/.next/server/app/settings/page.js.nft.json +1 -1
  144. package/web/.next/server/app/settings/page_client-reference-manifest.js +1 -1
  145. package/web/.next/server/app/skills/page/server-reference-manifest.json +6 -6
  146. package/web/.next/server/app/skills/page.js.nft.json +1 -1
  147. package/web/.next/server/app/skills/page_client-reference-manifest.js +1 -1
  148. package/web/.next/server/app/tools/page/server-reference-manifest.json +6 -6
  149. package/web/.next/server/app/tools/page.js.nft.json +1 -1
  150. package/web/.next/server/app/tools/page_client-reference-manifest.js +1 -1
  151. package/web/.next/server/app/version/page/server-reference-manifest.json +1 -1
  152. package/web/.next/server/app/version/page_client-reference-manifest.js +1 -1
  153. package/web/.next/server/chunks/403f9_next_dist_esm_build_templates_app-route_370c43b1.js +1 -1
  154. package/web/.next/server/chunks/403f9_next_dist_esm_build_templates_app-route_370c43b1.js.map +1 -1
  155. package/web/.next/server/chunks/[externals]_node:fs_ddf6f167._.js +3 -0
  156. package/web/.next/server/chunks/[externals]_node:fs_ddf6f167._.js.map +1 -0
  157. package/web/.next/server/chunks/[root-of-the-server]__3b72e8b0._.js +1 -1
  158. package/web/.next/server/chunks/[root-of-the-server]__3b72e8b0._.js.map +1 -1
  159. package/web/.next/server/chunks/[root-of-the-server]__42b7ab55._.js +1 -1
  160. package/web/.next/server/chunks/[root-of-the-server]__42b7ab55._.js.map +1 -1
  161. package/web/.next/server/chunks/[root-of-the-server]__a402b567._.js +1 -1
  162. package/web/.next/server/chunks/[root-of-the-server]__a62bd945._.js +3 -0
  163. package/web/.next/server/chunks/[root-of-the-server]__a62bd945._.js.map +1 -0
  164. package/web/.next/server/chunks/[root-of-the-server]__cd67a84c._.js +1 -1
  165. package/web/.next/server/chunks/[root-of-the-server]__cd67a84c._.js.map +1 -1
  166. package/web/.next/server/chunks/ssr/744ca_web_components_common_control-center-drawer_create-drawer-client_tsx_5e26fc0a._.js +1 -1
  167. package/web/.next/server/chunks/ssr/744ca_web_components_common_control-center-drawer_create-drawer-client_tsx_5e26fc0a._.js.map +1 -1
  168. package/web/.next/server/chunks/ssr/8ba4b_server_app_(dashboard)_@drawer_repository_[repositoryId]_page_actions_f30d0343.js +3 -0
  169. package/web/.next/server/chunks/ssr/8ba4b_server_app_(dashboard)_@drawer_repository_[repositoryId]_page_actions_f30d0343.js.map +1 -0
  170. package/web/.next/server/chunks/ssr/8ba4b_server_app_(dashboard)_repository_[repositoryId]_page_actions_9f1775bb.js +3 -0
  171. package/web/.next/server/chunks/ssr/8ba4b_server_app_(dashboard)_repository_[repositoryId]_page_actions_9f1775bb.js.map +1 -0
  172. package/web/.next/server/chunks/ssr/[root-of-the-server]__06fef644._.js +1 -1
  173. package/web/.next/server/chunks/ssr/[root-of-the-server]__2698e9f4._.js +3 -0
  174. package/web/.next/server/chunks/ssr/[root-of-the-server]__2698e9f4._.js.map +1 -0
  175. package/web/.next/server/chunks/ssr/[root-of-the-server]__545792ab._.js +1 -1
  176. package/web/.next/server/chunks/ssr/[root-of-the-server]__545792ab._.js.map +1 -1
  177. package/web/.next/server/chunks/ssr/[root-of-the-server]__6b17a22d._.js +1 -1
  178. package/web/.next/server/chunks/ssr/[root-of-the-server]__6b17a22d._.js.map +1 -1
  179. package/web/.next/server/chunks/ssr/[root-of-the-server]__6bb00d90._.js +2 -2
  180. package/web/.next/server/chunks/ssr/[root-of-the-server]__6bb00d90._.js.map +1 -1
  181. package/web/.next/server/chunks/ssr/[root-of-the-server]__804c006d._.js +1 -1
  182. package/web/.next/server/chunks/ssr/[root-of-the-server]__804c006d._.js.map +1 -1
  183. package/web/.next/server/chunks/ssr/[root-of-the-server]__8c553503._.js +2 -2
  184. package/web/.next/server/chunks/ssr/[root-of-the-server]__8e3bf5d7._.js +3 -0
  185. package/web/.next/server/chunks/ssr/[root-of-the-server]__8e3bf5d7._.js.map +1 -0
  186. package/web/.next/server/chunks/ssr/[root-of-the-server]__a022445f._.js +2 -2
  187. package/web/.next/server/chunks/ssr/[root-of-the-server]__a022445f._.js.map +1 -1
  188. package/web/.next/server/chunks/ssr/[root-of-the-server]__a7de2711._.js +2 -2
  189. package/web/.next/server/chunks/ssr/[root-of-the-server]__a7de2711._.js.map +1 -1
  190. package/web/.next/server/chunks/ssr/[root-of-the-server]__b724df9e._.js +1 -1
  191. package/web/.next/server/chunks/ssr/[root-of-the-server]__b724df9e._.js.map +1 -1
  192. package/web/.next/server/chunks/ssr/[root-of-the-server]__c07f9f79._.js +3 -0
  193. package/web/.next/server/chunks/ssr/[root-of-the-server]__c07f9f79._.js.map +1 -0
  194. package/web/.next/server/chunks/ssr/[root-of-the-server]__c605a375._.js +3 -0
  195. package/web/.next/server/chunks/ssr/[root-of-the-server]__c605a375._.js.map +1 -0
  196. package/web/.next/server/chunks/ssr/[root-of-the-server]__f646b99a._.js +3 -0
  197. package/web/.next/server/chunks/ssr/[root-of-the-server]__f646b99a._.js.map +1 -0
  198. package/web/.next/server/chunks/ssr/_0dc2cfd3._.js +1 -1
  199. package/web/.next/server/chunks/ssr/_0dc2cfd3._.js.map +1 -1
  200. package/web/.next/server/chunks/ssr/_135edb9c._.js +1 -1
  201. package/web/.next/server/chunks/ssr/_135edb9c._.js.map +1 -1
  202. package/web/.next/server/chunks/ssr/_1bb131c4._.js.map +1 -1
  203. package/web/.next/server/chunks/ssr/{_68cc9b82._.js → _1ced87ef._.js} +2 -2
  204. package/web/.next/server/chunks/ssr/{_68cc9b82._.js.map → _1ced87ef._.js.map} +1 -1
  205. package/web/.next/server/chunks/ssr/_2f6f48b8._.js +1 -1
  206. package/web/.next/server/chunks/ssr/_2f6f48b8._.js.map +1 -1
  207. package/web/.next/server/chunks/ssr/_affb27a3._.js +3 -0
  208. package/web/.next/server/chunks/ssr/{_73a34cb2._.js.map → _affb27a3._.js.map} +1 -1
  209. package/web/.next/server/chunks/ssr/_cb942e20._.js +3 -0
  210. package/web/.next/server/chunks/ssr/_cb942e20._.js.map +1 -0
  211. package/web/.next/server/chunks/ssr/_cc77a143._.js +1 -1
  212. package/web/.next/server/chunks/ssr/_cc77a143._.js.map +1 -1
  213. package/web/.next/server/chunks/ssr/b1a17_presentation_web_components_features_settings_settings-page-client_tsx_6ed9d5f8._.js +1 -1
  214. package/web/.next/server/chunks/ssr/b1a17_presentation_web_components_features_settings_settings-page-client_tsx_6ed9d5f8._.js.map +1 -1
  215. package/web/.next/server/chunks/ssr/{src_presentation_web_0835b28e._.js → src_presentation_web_5f039db1._.js} +3 -3
  216. package/web/.next/server/chunks/ssr/{src_presentation_web_0835b28e._.js.map → src_presentation_web_5f039db1._.js.map} +1 -1
  217. package/web/.next/server/chunks/ssr/src_presentation_web__next-internal_server_app_(dashboard)_page_actions_2a52b697.js +3 -0
  218. package/web/.next/server/chunks/ssr/src_presentation_web__next-internal_server_app_(dashboard)_page_actions_2a52b697.js.map +1 -0
  219. package/web/.next/server/chunks/ssr/src_presentation_web__next-internal_server_app_skills_page_actions_1fa8042e.js +1 -1
  220. package/web/.next/server/chunks/ssr/src_presentation_web__next-internal_server_app_skills_page_actions_1fa8042e.js.map +1 -1
  221. package/web/.next/server/chunks/ssr/src_presentation_web__next-internal_server_app_tools_page_actions_24684200.js +1 -1
  222. package/web/.next/server/chunks/ssr/src_presentation_web__next-internal_server_app_tools_page_actions_24684200.js.map +1 -1
  223. package/web/.next/server/chunks/ssr/{src_presentation_web_e8034a29._.js → src_presentation_web_c4337169._.js} +3 -3
  224. package/web/.next/server/chunks/ssr/{src_presentation_web_e8034a29._.js.map → src_presentation_web_c4337169._.js.map} +1 -1
  225. package/web/.next/server/chunks/ssr/src_presentation_web_ca99d62d._.js +1 -1
  226. package/web/.next/server/chunks/ssr/src_presentation_web_ca99d62d._.js.map +1 -1
  227. package/web/.next/server/chunks/ssr/src_presentation_web_components_bf50c527._.js +1 -1
  228. package/web/.next/server/chunks/ssr/src_presentation_web_components_de814675._.js +1 -1
  229. package/web/.next/server/chunks/ssr/src_presentation_web_components_features_control-center_7ac3562e._.js +1 -1
  230. package/web/.next/server/chunks/ssr/src_presentation_web_components_features_control-center_7ac3562e._.js.map +1 -1
  231. package/web/.next/server/pages/500.html +2 -2
  232. package/web/.next/server/server-reference-manifest.js +1 -1
  233. package/web/.next/server/server-reference-manifest.json +311 -240
  234. package/web/.next/static/chunks/04b2108495415052.js +1 -0
  235. package/web/.next/static/chunks/3911a7175044e784.js +1 -0
  236. package/web/.next/static/chunks/574116ea7de4c18d.js +1 -0
  237. package/web/.next/static/chunks/{8ded2620c2272c27.js → 5c4ada27bc57d0a4.js} +2 -2
  238. package/web/.next/static/chunks/68c5260cce07b4de.js +1 -0
  239. package/web/.next/static/chunks/{5186e2254580afd1.js → 780f705bfe91f7fc.js} +1 -1
  240. package/web/.next/static/chunks/991df1233214b238.css +1 -0
  241. package/web/.next/static/chunks/{4b58ac6e7721f9ea.js → a0d1d6263db19600.js} +1 -1
  242. package/web/.next/static/chunks/{0cc5f5ca1696267a.js → aa9c03b455fc4a49.js} +1 -1
  243. package/web/.next/static/chunks/{f22c2cdecc7a523b.js → aee3590a26cac4f3.js} +1 -1
  244. package/web/.next/static/chunks/cce8416ed0cbc011.js +2 -0
  245. package/web/.next/static/chunks/{4c22a50608db401a.js → f27126bcef6cbaa9.js} +1 -1
  246. package/web/.next/server/chunks/[root-of-the-server]__0fe7788d._.js +0 -3
  247. package/web/.next/server/chunks/[root-of-the-server]__0fe7788d._.js.map +0 -1
  248. package/web/.next/server/chunks/ssr/8ba4b_server_app_(dashboard)_@drawer_repository_[repositoryId]_page_actions_ed372306.js +0 -3
  249. package/web/.next/server/chunks/ssr/8ba4b_server_app_(dashboard)_@drawer_repository_[repositoryId]_page_actions_ed372306.js.map +0 -1
  250. package/web/.next/server/chunks/ssr/8ba4b_server_app_(dashboard)_repository_[repositoryId]_page_actions_32e26434.js +0 -3
  251. package/web/.next/server/chunks/ssr/8ba4b_server_app_(dashboard)_repository_[repositoryId]_page_actions_32e26434.js.map +0 -1
  252. package/web/.next/server/chunks/ssr/[root-of-the-server]__3b14e5a0._.js +0 -3
  253. package/web/.next/server/chunks/ssr/[root-of-the-server]__3b14e5a0._.js.map +0 -1
  254. package/web/.next/server/chunks/ssr/[root-of-the-server]__8b59c03e._.js +0 -3
  255. package/web/.next/server/chunks/ssr/[root-of-the-server]__8b59c03e._.js.map +0 -1
  256. package/web/.next/server/chunks/ssr/[root-of-the-server]__994ad9fe._.js +0 -3
  257. package/web/.next/server/chunks/ssr/[root-of-the-server]__994ad9fe._.js.map +0 -1
  258. package/web/.next/server/chunks/ssr/[root-of-the-server]__9f155c0e._.js +0 -3
  259. package/web/.next/server/chunks/ssr/[root-of-the-server]__9f155c0e._.js.map +0 -1
  260. package/web/.next/server/chunks/ssr/[root-of-the-server]__c9c1cfee._.js +0 -3
  261. package/web/.next/server/chunks/ssr/[root-of-the-server]__c9c1cfee._.js.map +0 -1
  262. package/web/.next/server/chunks/ssr/_0314651a._.js +0 -3
  263. package/web/.next/server/chunks/ssr/_0314651a._.js.map +0 -1
  264. package/web/.next/server/chunks/ssr/_73a34cb2._.js +0 -3
  265. package/web/.next/server/chunks/ssr/src_presentation_web__next-internal_server_app_(dashboard)_page_actions_e99d78dd.js +0 -3
  266. package/web/.next/server/chunks/ssr/src_presentation_web__next-internal_server_app_(dashboard)_page_actions_e99d78dd.js.map +0 -1
  267. package/web/.next/static/chunks/0d2af96e64960ef5.css +0 -1
  268. package/web/.next/static/chunks/2132807f96110232.js +0 -1
  269. package/web/.next/static/chunks/4562ee849ea13c3a.js +0 -1
  270. package/web/.next/static/chunks/9fdfff0a8c69ecd2.js +0 -2
  271. package/web/.next/static/chunks/c6a68bd98c2c0446.js +0 -1
  272. package/web/.next/static/chunks/f27e3d3959bf91e6.js +0 -1
  273. /package/web/.next/static/{Fg0DqzWA5hDmVmj5X9iq- → VBPTE7xcWBAoQkxtk58nb}/_buildManifest.js +0 -0
  274. /package/web/.next/static/{Fg0DqzWA5hDmVmj5X9iq- → VBPTE7xcWBAoQkxtk58nb}/_clientMiddlewareManifest.json +0 -0
  275. /package/web/.next/static/{Fg0DqzWA5hDmVmj5X9iq- → VBPTE7xcWBAoQkxtk58nb}/_ssgManifest.js +0 -0
@@ -1 +1 @@
1
- {"version":3,"file":"get-feature-phase-timings.d.ts","sourceRoot":"","sources":["../../../../../../src/presentation/web/app/actions/get-feature-phase-timings.ts"],"names":[],"mappings":"AAMA,MAAM,WAAW,eAAe;IAC9B,UAAU,EAAE,MAAM,CAAC;IACnB,KAAK,EAAE,MAAM,CAAC;IACd,SAAS,EAAE,MAAM,CAAC;IAClB,WAAW,CAAC,EAAE,MAAM,CAAC;IACrB,UAAU,CAAC,EAAE,MAAM,CAAC;IACpB,iBAAiB,CAAC,EAAE,MAAM,CAAC;IAC3B,cAAc,CAAC,EAAE,MAAM,CAAC;IACxB,WAAW,CAAC,EAAE,MAAM,CAAC;IACrB,YAAY,CAAC,EAAE,MAAM,CAAC;CACvB;AAED,MAAM,WAAW,qBAAqB;IACpC,SAAS,EAAE,MAAM,CAAC;IAClB,OAAO,EAAE,MAAM,CAAC;IAChB,KAAK,CAAC,EAAE,MAAM,CAAC;IACf,SAAS,CAAC,EAAE,MAAM,CAAC;IACnB,WAAW,CAAC,EAAE,MAAM,EAAE,CAAC;CACxB;AAED,KAAK,qBAAqB,GACtB;IAAE,OAAO,EAAE,eAAe,EAAE,CAAC;IAAC,iBAAiB,EAAE,qBAAqB,EAAE,CAAA;CAAE,GAC1E;IAAE,KAAK,EAAE,MAAM,CAAA;CAAE,CAAC;AAEtB,wBAAsB,sBAAsB,CAAC,SAAS,EAAE,MAAM,GAAG,OAAO,CAAC,qBAAqB,CAAC,CA6B9F"}
1
+ {"version":3,"file":"get-feature-phase-timings.d.ts","sourceRoot":"","sources":["../../../../../../src/presentation/web/app/actions/get-feature-phase-timings.ts"],"names":[],"mappings":"AAMA,MAAM,WAAW,eAAe;IAC9B,UAAU,EAAE,MAAM,CAAC;IACnB,KAAK,EAAE,MAAM,CAAC;IACd,SAAS,EAAE,MAAM,CAAC;IAClB,WAAW,CAAC,EAAE,MAAM,CAAC;IACrB,UAAU,CAAC,EAAE,MAAM,CAAC;IACpB,iBAAiB,CAAC,EAAE,MAAM,CAAC;IAC3B,cAAc,CAAC,EAAE,MAAM,CAAC;IACxB,WAAW,CAAC,EAAE,MAAM,CAAC;IACrB,YAAY,CAAC,EAAE,MAAM,CAAC;IACtB,wBAAwB,CAAC,EAAE,MAAM,CAAC;IAClC,oBAAoB,CAAC,EAAE,MAAM,CAAC;IAC9B,OAAO,CAAC,EAAE,MAAM,CAAC;IACjB,QAAQ,CAAC,EAAE,MAAM,CAAC;IAClB,aAAa,CAAC,EAAE,MAAM,CAAC;CACxB;AAED,MAAM,WAAW,qBAAqB;IACpC,SAAS,EAAE,MAAM,CAAC;IAClB,OAAO,EAAE,MAAM,CAAC;IAChB,KAAK,CAAC,EAAE,MAAM,CAAC;IACf,SAAS,CAAC,EAAE,MAAM,CAAC;IACnB,WAAW,CAAC,EAAE,MAAM,EAAE,CAAC;CACxB;AAED,KAAK,qBAAqB,GACtB;IAAE,OAAO,EAAE,eAAe,EAAE,CAAC;IAAC,iBAAiB,EAAE,qBAAqB,EAAE,CAAA;CAAE,GAC1E;IAAE,KAAK,EAAE,MAAM,CAAA;CAAE,CAAC;AAEtB,wBAAsB,sBAAsB,CAAC,SAAS,EAAE,MAAM,GAAG,OAAO,CAAC,qBAAqB,CAAC,CAoC9F"}
@@ -17,6 +17,11 @@ export async function getFeaturePhaseTimings(featureId) {
17
17
  approvalWaitMs: t.approvalWaitMs != null ? Number(t.approvalWaitMs) : undefined,
18
18
  inputTokens: t.inputTokens != null ? Number(t.inputTokens) : undefined,
19
19
  outputTokens: t.outputTokens != null ? Number(t.outputTokens) : undefined,
20
+ cacheCreationInputTokens: t.cacheCreationInputTokens != null ? Number(t.cacheCreationInputTokens) : undefined,
21
+ cacheReadInputTokens: t.cacheReadInputTokens != null ? Number(t.cacheReadInputTokens) : undefined,
22
+ costUsd: t.costUsd != null ? Number(t.costUsd) : undefined,
23
+ numTurns: t.numTurns ?? undefined,
24
+ durationApiMs: t.durationApiMs != null ? Number(t.durationApiMs) : undefined,
20
25
  }));
21
26
  // Read rejection feedback from spec.yaml
22
27
  const rejectionFeedback = await readRejectionFeedback(featureId);
@@ -1 +1 @@
1
- {"version":3,"file":"reject-feature.d.ts","sourceRoot":"","sources":["../../../../../../src/presentation/web/app/actions/reject-feature.ts"],"names":[],"mappings":"AAMA,wBAAsB,aAAa,CACjC,SAAS,EAAE,MAAM,EACjB,QAAQ,EAAE,MAAM,EAChB,WAAW,CAAC,EAAE,MAAM,EAAE,GACrB,OAAO,CAAC;IACT,QAAQ,EAAE,OAAO,CAAC;IAClB,SAAS,CAAC,EAAE,MAAM,CAAC;IACnB,gBAAgB,CAAC,EAAE,OAAO,CAAC;IAC3B,KAAK,CAAC,EAAE,MAAM,CAAC;CAChB,CAAC,CAqCD"}
1
+ {"version":3,"file":"reject-feature.d.ts","sourceRoot":"","sources":["../../../../../../src/presentation/web/app/actions/reject-feature.ts"],"names":[],"mappings":"AAWA,wBAAsB,aAAa,CACjC,SAAS,EAAE,MAAM,EACjB,QAAQ,EAAE,MAAM,EAChB,WAAW,CAAC,EAAE,MAAM,EAAE,GACrB,OAAO,CAAC;IACT,QAAQ,EAAE,OAAO,CAAC;IAClB,SAAS,CAAC,EAAE,MAAM,CAAC;IACnB,gBAAgB,CAAC,EAAE,OAAO,CAAC;IAC3B,KAAK,CAAC,EAAE,MAAM,CAAC;CAChB,CAAC,CA8CD"}
@@ -1,5 +1,7 @@
1
1
  'use server';
2
2
  import { resolve } from '../../lib/server-container.js';
3
+ import { AgentRunStatus } from '../../../../../packages/core/src/domain/generated/output.js';
4
+ const ERROR_STATUSES = new Set([AgentRunStatus.failed, AgentRunStatus.interrupted]);
3
5
  export async function rejectFeature(featureId, feedback, attachments) {
4
6
  if (!featureId.trim()) {
5
7
  return { rejected: false, error: 'Feature id is required' };
@@ -16,6 +18,13 @@ export async function rejectFeature(featureId, feedback, attachments) {
16
18
  if (!feature.agentRunId) {
17
19
  return { rejected: false, error: 'Feature has no agent run' };
18
20
  }
21
+ const runRepo = resolve('IAgentRunRepository');
22
+ const run = await runRepo.findById(feature.agentRunId);
23
+ if (run && ERROR_STATUSES.has(run.status)) {
24
+ const resumeUseCase = resolve('ResumeFeatureUseCase');
25
+ await resumeUseCase.execute(featureId, { promptPrefix: feedback });
26
+ return { rejected: true, iteration: 1 };
27
+ }
19
28
  const rejectUseCase = resolve('RejectAgentRunUseCase');
20
29
  const result = await rejectUseCase.execute(feature.agentRunId, feedback, attachments);
21
30
  if (!result.rejected) {
@@ -0,0 +1,5 @@
1
+ export declare function stopFeature(featureId: string): Promise<{
2
+ stopped: boolean;
3
+ error?: string;
4
+ }>;
5
+ //# sourceMappingURL=stop-feature.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"stop-feature.d.ts","sourceRoot":"","sources":["../../../../../../src/presentation/web/app/actions/stop-feature.ts"],"names":[],"mappings":"AAMA,wBAAsB,WAAW,CAC/B,SAAS,EAAE,MAAM,GAChB,OAAO,CAAC;IAAE,OAAO,EAAE,OAAO,CAAC;IAAC,KAAK,CAAC,EAAE,MAAM,CAAA;CAAE,CAAC,CAiC/C"}
@@ -0,0 +1,30 @@
1
+ 'use server';
2
+ import { resolve } from '../../lib/server-container.js';
3
+ export async function stopFeature(featureId) {
4
+ if (!featureId.trim()) {
5
+ return { stopped: false, error: 'Feature id is required' };
6
+ }
7
+ try {
8
+ // Find the active agent run for this feature
9
+ const runRepo = resolve('IAgentRunRepository');
10
+ const allRuns = await runRepo.list();
11
+ const activeRun = allRuns.find((r) => r.featureId === featureId &&
12
+ r.status !== 'completed' &&
13
+ r.status !== 'failed' &&
14
+ r.status !== 'interrupted' &&
15
+ r.status !== 'cancelled');
16
+ if (!activeRun) {
17
+ return { stopped: false, error: 'No active agent run found for this feature' };
18
+ }
19
+ const useCase = resolve('StopAgentRunUseCase');
20
+ const result = await useCase.execute(activeRun.id);
21
+ if (!result.stopped) {
22
+ return { stopped: false, error: result.reason };
23
+ }
24
+ return { stopped: true };
25
+ }
26
+ catch (error) {
27
+ const message = error instanceof Error ? error.message : 'Failed to stop agent';
28
+ return { stopped: false, error: message };
29
+ }
30
+ }
@@ -1 +1 @@
1
- {"version":3,"file":"route.d.ts","sourceRoot":"","sources":["../../../../../../../src/presentation/web/app/api/npm-version/route.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,YAAY,EAAE,MAAM,aAAa,CAAC;AAE3C,wBAAsB,GAAG,IAAI,OAAO,CAAC,YAAY,CAAC,CAejD"}
1
+ {"version":3,"file":"route.d.ts","sourceRoot":"","sources":["../../../../../../../src/presentation/web/app/api/npm-version/route.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,YAAY,EAAE,MAAM,aAAa,CAAC;AAK3C,wBAAsB,GAAG,IAAI,OAAO,CAAC,YAAY,CAAC,CAsBjD"}
@@ -1,5 +1,11 @@
1
1
  import { NextResponse } from 'next/server';
2
+ const CACHE_TTL_MS = 5 * 60_000; // 5 minutes
3
+ let cachedVersion = null;
2
4
  export async function GET() {
5
+ // Return cached value if fresh
6
+ if (cachedVersion && Date.now() - cachedVersion.fetchedAt < CACHE_TTL_MS) {
7
+ return NextResponse.json({ latest: cachedVersion.latest });
8
+ }
3
9
  const packageName = '@shepai/cli';
4
10
  try {
5
11
  const res = await fetch(`https://registry.npmjs.org/${packageName}/latest`, {
@@ -9,7 +15,9 @@ export async function GET() {
9
15
  return NextResponse.json({ error: `npm registry returned ${res.status}` }, { status: 502 });
10
16
  }
11
17
  const data = (await res.json());
12
- return NextResponse.json({ latest: data.version ?? null });
18
+ const latest = data.version ?? null;
19
+ cachedVersion = { latest, fetchedAt: Date.now() };
20
+ return NextResponse.json({ latest });
13
21
  }
14
22
  catch (error) {
15
23
  const message = error instanceof Error ? error.message : 'Failed to check npm version';
@@ -1 +1 @@
1
- {"version":3,"file":"route.d.ts","sourceRoot":"","sources":["../../../../../../../src/presentation/web/app/api/sessions/route.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,YAAY,EAAE,MAAM,aAAa,CAAC;AAK3C,eAAO,MAAM,OAAO,kBAAkB,CAAC;AA4QvC;;;;;GAKG;AACH,wBAAsB,GAAG,CAAC,OAAO,EAAE,OAAO;;;;YA/QpC,MAAM;mBACC,MAAM;iBACR,MAAM,GAAG,IAAI;sBACR,MAAM;wBACJ,MAAM,GAAG,IAAI;uBACd,MAAM,GAAG,IAAI;mBACjB,MAAM,GAAG,IAAI;qBACX,MAAM;kBACT,MAAM;;IAoSjB"}
1
+ {"version":3,"file":"route.d.ts","sourceRoot":"","sources":["../../../../../../../src/presentation/web/app/api/sessions/route.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,YAAY,EAAE,MAAM,aAAa,CAAC;AAK3C,eAAO,MAAM,OAAO,kBAAkB,CAAC;AAgTvC;;;;;GAKG;AACH,wBAAsB,GAAG,CAAC,OAAO,EAAE,OAAO;;;;YAnTpC,MAAM;mBACC,MAAM;iBACR,MAAM,GAAG,IAAI;sBACR,MAAM;wBACJ,MAAM,GAAG,IAAI;uBACd,MAAM,GAAG,IAAI;mBACjB,MAAM,GAAG,IAAI;qBACX,MAAM;kBACT,MAAM;;IAwUjB"}
@@ -1,7 +1,7 @@
1
1
  import { NextResponse } from 'next/server';
2
2
  import { homedir } from 'node:os';
3
3
  import { join } from 'node:path';
4
- import { readdir, stat, readFile } from 'node:fs/promises';
4
+ import { readdir, stat } from 'node:fs/promises';
5
5
  export const dynamic = 'force-dynamic';
6
6
  // ── Path encoding helpers ─────────────────────────────────────────────
7
7
  /**
@@ -49,14 +49,32 @@ async function scanClaudeSessions(repositoryPath, limit) {
49
49
  .map((r) => r.value)
50
50
  .filter((s) => s !== null);
51
51
  }
52
+ /**
53
+ * Read the first N bytes of a file to extract preview and timestamps
54
+ * without loading the entire (potentially multi-MB) session file.
55
+ */
56
+ const PREVIEW_READ_BYTES = 8_192; // 8KB is enough for first few messages
52
57
  async function parseClaudeSession(filePath, fileName, mtime, repositoryPath) {
53
- const content = await readFile(filePath, 'utf-8');
54
- const lines = content.split('\n').filter((l) => l.trim());
58
+ const { createReadStream } = await import('node:fs');
55
59
  const id = fileName.replace('.jsonl', '');
60
+ // Read only the first chunk to extract preview and first timestamp
56
61
  let preview = null;
57
- let messageCount = 0;
58
62
  let firstTimestamp = null;
59
- let lastTimestamp = null;
63
+ let messageCount = 0;
64
+ const head = await new Promise((resolve) => {
65
+ const chunks = [];
66
+ let size = 0;
67
+ const stream = createReadStream(filePath, { end: PREVIEW_READ_BYTES - 1 });
68
+ stream.on('data', (chunk) => {
69
+ chunks.push(chunk);
70
+ size += chunk.length;
71
+ });
72
+ stream.on('end', () => resolve(Buffer.concat(chunks, size).toString('utf-8')));
73
+ stream.on('error', () => resolve(''));
74
+ });
75
+ if (!head)
76
+ return null;
77
+ const lines = head.split('\n').filter((l) => l.trim());
60
78
  for (const line of lines) {
61
79
  try {
62
80
  const entry = JSON.parse(line);
@@ -66,7 +84,6 @@ async function parseClaudeSession(filePath, fileName, mtime, repositoryPath) {
66
84
  messageCount++;
67
85
  if (entry.timestamp) {
68
86
  firstTimestamp ??= entry.timestamp;
69
- lastTimestamp = entry.timestamp;
70
87
  }
71
88
  if (role === 'user' && preview === null) {
72
89
  preview = extractText(entry.message?.content);
@@ -80,14 +97,16 @@ async function parseClaudeSession(filePath, fileName, mtime, repositoryPath) {
80
97
  }
81
98
  if (messageCount === 0)
82
99
  return null;
100
+ // Use mtime as lastMessageAt — avoids reading entire file for last line
101
+ const mtimeIso = new Date(mtime).toISOString();
83
102
  return {
84
103
  id,
85
104
  agentType: 'claude-code',
86
105
  preview,
87
106
  messageCount,
88
107
  firstMessageAt: firstTimestamp,
89
- lastMessageAt: lastTimestamp,
90
- createdAt: firstTimestamp ?? new Date(mtime).toISOString(),
108
+ lastMessageAt: mtimeIso,
109
+ createdAt: firstTimestamp ?? mtimeIso,
91
110
  projectPath: repositoryPath,
92
111
  filePath,
93
112
  _mtime: mtime,
@@ -144,11 +163,25 @@ async function scanCursorSessions(repositoryPath, limit) {
144
163
  .filter((s) => s !== null);
145
164
  }
146
165
  async function parseCursorSession(filePath, fileName, mtime, repositoryPath) {
147
- const content = await readFile(filePath, 'utf-8');
148
- const lines = content.split('\n').filter((l) => l.trim());
166
+ const { createReadStream } = await import('node:fs');
149
167
  const id = fileName.replace('.jsonl', '');
168
+ // Read only the first chunk for preview extraction
169
+ const head = await new Promise((resolve) => {
170
+ const chunks = [];
171
+ let size = 0;
172
+ const stream = createReadStream(filePath, { end: PREVIEW_READ_BYTES - 1 });
173
+ stream.on('data', (chunk) => {
174
+ chunks.push(chunk);
175
+ size += chunk.length;
176
+ });
177
+ stream.on('end', () => resolve(Buffer.concat(chunks, size).toString('utf-8')));
178
+ stream.on('error', () => resolve(''));
179
+ });
180
+ if (!head)
181
+ return null;
150
182
  let preview = null;
151
183
  let messageCount = 0;
184
+ const lines = head.split('\n').filter((l) => l.trim());
152
185
  for (const line of lines) {
153
186
  try {
154
187
  const entry = JSON.parse(line);
@@ -1 +1 @@
1
- {"version":3,"file":"activity-tab.d.ts","sourceRoot":"","sources":["../../../../../../../src/presentation/web/components/common/feature-drawer-tabs/activity-tab.tsx"],"names":[],"mappings":"AAIA,OAAO,KAAK,EACV,eAAe,EACf,qBAAqB,EACtB,MAAM,yCAAyC,CAAC;AAqDjD,MAAM,WAAW,gBAAgB;IAC/B,OAAO,EAAE,eAAe,EAAE,GAAG,IAAI,CAAC;IAClC,OAAO,EAAE,OAAO,CAAC;IACjB,KAAK,EAAE,MAAM,GAAG,IAAI,CAAC;IACrB,iBAAiB,CAAC,EAAE,qBAAqB,EAAE,CAAC;CAC7C;AA6BD;;;;;;;GAOG;AACH,MAAM,WAAW,iBAAiB;IAChC,+BAA+B;IAC/B,MAAM,EAAE,MAAM,CAAC;IACf,0CAA0C;IAC1C,OAAO,EAAE,eAAe,EAAE,CAAC;IAC3B,mEAAmE;IACnE,gBAAgB,CAAC,EAAE,MAAM,CAAC;IAC1B,8DAA8D;IAC9D,oBAAoB,CAAC,EAAE,MAAM,EAAE,CAAC;CACjC;AAED;;;;;;;;;GASG;AACH,wBAAgB,sBAAsB,CACpC,OAAO,EAAE,eAAe,EAAE,EAC1B,QAAQ,CAAC,EAAE,qBAAqB,EAAE,GACjC,iBAAiB,EAAE,CAgErB;AAMD,wBAAgB,WAAW,CAAC,EAAE,OAAO,EAAE,OAAO,EAAE,KAAK,EAAE,iBAAiB,EAAE,EAAE,gBAAgB,2CAmE3F"}
1
+ {"version":3,"file":"activity-tab.d.ts","sourceRoot":"","sources":["../../../../../../../src/presentation/web/components/common/feature-drawer-tabs/activity-tab.tsx"],"names":[],"mappings":"AAkBA,OAAO,KAAK,EACV,eAAe,EACf,qBAAqB,EACtB,MAAM,yCAAyC,CAAC;AAmEjD,MAAM,WAAW,gBAAgB;IAC/B,OAAO,EAAE,eAAe,EAAE,GAAG,IAAI,CAAC;IAClC,OAAO,EAAE,OAAO,CAAC;IACjB,KAAK,EAAE,MAAM,GAAG,IAAI,CAAC;IACrB,iBAAiB,CAAC,EAAE,qBAAqB,EAAE,CAAC;CAC7C;AAmED;;;;;;;GAOG;AACH,MAAM,WAAW,iBAAiB;IAChC,+BAA+B;IAC/B,MAAM,EAAE,MAAM,CAAC;IACf,0CAA0C;IAC1C,OAAO,EAAE,eAAe,EAAE,CAAC;IAC3B,mEAAmE;IACnE,gBAAgB,CAAC,EAAE,MAAM,CAAC;IAC1B,8DAA8D;IAC9D,oBAAoB,CAAC,EAAE,MAAM,EAAE,CAAC;CACjC;AAED;;;;;;;;;GASG;AACH,wBAAgB,sBAAsB,CACpC,OAAO,EAAE,eAAe,EAAE,EAC1B,QAAQ,CAAC,EAAE,qBAAqB,EAAE,GACjC,iBAAiB,EAAE,CAgErB;AA6BD,wBAAgB,WAAW,CAAC,EAAE,OAAO,EAAE,OAAO,EAAE,KAAK,EAAE,iBAAiB,EAAE,EAAE,gBAAgB,2CAqE3F"}
@@ -1,7 +1,7 @@
1
1
  'use client';
2
2
  import { jsx as _jsx, jsxs as _jsxs, Fragment as _Fragment } from "react/jsx-runtime";
3
3
  import { useState, useEffect, useRef } from 'react';
4
- import { Loader2, AlertCircle, Clock, Zap } from 'lucide-react';
4
+ import { Loader2, AlertCircle, Clock, Zap, DollarSign, Play, RotateCcw, CheckCircle2, XCircle, Square, Ban, MessageSquare, Timer, } from 'lucide-react';
5
5
  import { InlineAttachments } from '../../common/inline-attachments/index.js';
6
6
  import { formatDuration } from '../../../lib/format-duration.js';
7
7
  /**
@@ -51,6 +51,21 @@ function formatTokens(count) {
51
51
  return `${(count / 1_000).toFixed(1)}K`;
52
52
  return String(count);
53
53
  }
54
+ /** Format a timestamp to a short local time string (e.g. "10:05:30 AM"). */
55
+ function formatTimestamp(value) {
56
+ const d = value instanceof Date ? value : new Date(String(value));
57
+ if (Number.isNaN(d.getTime()))
58
+ return '';
59
+ return d.toLocaleTimeString([], { hour: '2-digit', minute: '2-digit', second: '2-digit' });
60
+ }
61
+ /** Format a USD cost with appropriate precision. */
62
+ function formatCost(usd) {
63
+ if (usd >= 1)
64
+ return `$${usd.toFixed(2)}`;
65
+ if (usd >= 0.01)
66
+ return `$${usd.toFixed(3)}`;
67
+ return `$${usd.toFixed(4)}`;
68
+ }
54
69
  const NODE_TO_PHASE = {
55
70
  analyze: 'Analyzing',
56
71
  requirements: 'Requirements',
@@ -60,13 +75,48 @@ const NODE_TO_PHASE = {
60
75
  merge: 'Merging',
61
76
  };
62
77
  const LIFECYCLE_EVENTS = {
63
- 'run:started': { label: 'started', colorClass: 'text-blue-600' },
64
- 'run:resumed': { label: 'resumed', colorClass: 'text-blue-600' },
65
- 'run:completed': { label: 'completed', colorClass: 'text-emerald-600' },
66
- 'run:failed': { label: 'failed', colorClass: 'text-red-600' },
67
- 'run:stopped': { label: 'stopped', colorClass: 'text-amber-600' },
68
- 'run:crashed': { label: 'crashed', colorClass: 'text-red-600' },
69
- 'run:rejected': { label: 'rejected', colorClass: 'text-orange-600' },
78
+ 'run:started': {
79
+ label: 'started',
80
+ colorClass: 'text-blue-600',
81
+ bgClass: 'bg-blue-50 dark:bg-blue-950/30',
82
+ icon: Play,
83
+ },
84
+ 'run:resumed': {
85
+ label: 'resumed',
86
+ colorClass: 'text-blue-600',
87
+ bgClass: 'bg-blue-50 dark:bg-blue-950/30',
88
+ icon: RotateCcw,
89
+ },
90
+ 'run:completed': {
91
+ label: 'completed',
92
+ colorClass: 'text-emerald-600',
93
+ bgClass: 'bg-emerald-50 dark:bg-emerald-950/30',
94
+ icon: CheckCircle2,
95
+ },
96
+ 'run:failed': {
97
+ label: 'failed',
98
+ colorClass: 'text-red-600',
99
+ bgClass: 'bg-red-50 dark:bg-red-950/30',
100
+ icon: XCircle,
101
+ },
102
+ 'run:stopped': {
103
+ label: 'stopped',
104
+ colorClass: 'text-amber-600',
105
+ bgClass: 'bg-amber-50 dark:bg-amber-950/30',
106
+ icon: Square,
107
+ },
108
+ 'run:crashed': {
109
+ label: 'crashed',
110
+ colorClass: 'text-red-600',
111
+ bgClass: 'bg-red-50 dark:bg-red-950/30',
112
+ icon: XCircle,
113
+ },
114
+ 'run:rejected': {
115
+ label: 'rejected',
116
+ colorClass: 'text-orange-600',
117
+ bgClass: 'bg-orange-50 dark:bg-orange-950/30',
118
+ icon: Ban,
119
+ },
70
120
  };
71
121
  function isLifecycleEvent(phase) {
72
122
  return phase.startsWith('run:');
@@ -138,6 +188,26 @@ export function buildLifecycleTimeline(timings, feedback) {
138
188
  }
139
189
  return iterations;
140
190
  }
191
+ /** Determine the outcome status of an iteration */
192
+ function getIterationOutcome(iteration) {
193
+ const lastLifecycle = [...iteration.timings].reverse().find((t) => isLifecycleEvent(t.phase));
194
+ if (!lastLifecycle)
195
+ return null;
196
+ switch (lastLifecycle.phase) {
197
+ case 'run:rejected':
198
+ return { label: 'Rejected', colorClass: 'text-orange-600', dotClass: 'bg-orange-500' };
199
+ case 'run:completed':
200
+ return { label: 'Completed', colorClass: 'text-emerald-600', dotClass: 'bg-emerald-500' };
201
+ case 'run:failed':
202
+ return { label: 'Failed', colorClass: 'text-red-600', dotClass: 'bg-red-500' };
203
+ case 'run:crashed':
204
+ return { label: 'Crashed', colorClass: 'text-red-600', dotClass: 'bg-red-500' };
205
+ case 'run:stopped':
206
+ return { label: 'Stopped', colorClass: 'text-amber-600', dotClass: 'bg-amber-500' };
207
+ default:
208
+ return null;
209
+ }
210
+ }
141
211
  /* ---------------------------------------------------------------------------
142
212
  * Component
143
213
  * ------------------------------------------------------------------------- */
@@ -147,10 +217,10 @@ export function ActivityTab({ timings, loading, error, rejectionFeedback }) {
147
217
  return (_jsx("div", { "data-testid": "activity-tab-loading", className: "flex items-center justify-center p-8", children: _jsx(Loader2, { className: "text-muted-foreground h-6 w-6 animate-spin" }) }));
148
218
  }
149
219
  if (error) {
150
- return (_jsxs("div", { className: "flex items-center gap-2 p-4 text-sm text-red-600", children: [_jsx(AlertCircle, { className: "h-4 w-4 shrink-0" }), _jsx("span", { children: error })] }));
220
+ return (_jsxs("div", { className: "flex items-center gap-2 p-4 text-base text-red-600", children: [_jsx(AlertCircle, { className: "h-4 w-4 shrink-0" }), _jsx("span", { children: error })] }));
151
221
  }
152
222
  if (!timings || timings.length === 0) {
153
- return (_jsxs("div", { className: "flex flex-col items-center justify-center gap-2 p-8", children: [_jsx(Clock, { className: "text-muted-foreground h-8 w-8" }), _jsx("p", { className: "text-muted-foreground text-sm", children: "No activity recorded yet" })] }));
223
+ return (_jsxs("div", { className: "flex flex-col items-center justify-center gap-2 p-8", children: [_jsx(Clock, { className: "text-muted-foreground h-8 w-8" }), _jsx("p", { className: "text-muted-foreground text-base", children: "No activity recorded yet" })] }));
154
224
  }
155
225
  const nodeTimings = timings.filter((t) => !isLifecycleEvent(t.phase));
156
226
  const maxDurationMs = Math.max(...nodeTimings.map((t) => getEffectiveDuration(t, now)), ...nodeTimings.map((t) => t.approvalWaitMs ?? 0), 0);
@@ -160,35 +230,37 @@ export function ActivityTab({ timings, loading, error, rejectionFeedback }) {
160
230
  const totalWaitMs = nodeTimings.reduce((sum, t) => sum + (t.approvalWaitMs ?? 0), 0);
161
231
  const totalInputTokens = nodeTimings.reduce((sum, t) => sum + (t.inputTokens ?? 0), 0);
162
232
  const totalOutputTokens = nodeTimings.reduce((sum, t) => sum + (t.outputTokens ?? 0), 0);
163
- return (_jsxs("div", { className: "flex flex-col gap-4 p-4", children: [_jsx("div", { "data-testid": "activity-timings", className: "flex flex-col gap-3", children: iterations.map((iteration) => (_jsx(IterationGroup, { iteration: iteration, showHeader: hasMultipleIterations, maxDurationMs: maxDurationMs, now: now }, iteration.number))) }), totalExecMs > 0 ? (_jsx(SummaryTotals, { totalExecMs: totalExecMs, totalWaitMs: totalWaitMs, totalInputTokens: totalInputTokens, totalOutputTokens: totalOutputTokens })) : null] }));
233
+ const totalCostUsd = nodeTimings.reduce((sum, t) => sum + (t.costUsd ?? 0), 0);
234
+ return (_jsxs("div", { className: "flex flex-col gap-3 p-4", children: [_jsx("div", { "data-testid": "activity-timings", className: "flex flex-col gap-3", children: iterations.map((iteration) => (_jsx(IterationGroup, { iteration: iteration, showHeader: hasMultipleIterations, maxDurationMs: maxDurationMs, now: now }, iteration.number))) }), totalExecMs > 0 ? (_jsx(SummaryTotals, { totalExecMs: totalExecMs, totalWaitMs: totalWaitMs, totalInputTokens: totalInputTokens, totalOutputTokens: totalOutputTokens, totalCostUsd: totalCostUsd })) : null] }));
164
235
  }
165
236
  /* ---------------------------------------------------------------------------
166
237
  * Iteration group — one cycle of work
167
238
  * ------------------------------------------------------------------------- */
168
239
  function IterationGroup({ iteration, showHeader, maxDurationMs, now, }) {
169
- return (_jsxs("div", { "data-testid": `iteration-${iteration.number}`, className: "flex flex-col gap-1.5", children: [showHeader ? (_jsxs("div", { className: "text-muted-foreground text-xs font-medium", children: ["Iteration ", iteration.number] })) : null, iteration.timings.map((t) => {
170
- if (isLifecycleEvent(t.phase)) {
171
- // For run:rejected, the message comes from the iteration, not a separate map
172
- const isRejection = t.phase === 'run:rejected';
173
- return (_jsx(LifecycleEventRow, { timing: t, message: isRejection ? iteration.rejectionMessage : undefined, attachments: isRejection ? iteration.rejectionAttachments : undefined }, `${t.agentRunId}-${t.phase}-${t.startedAt}`));
174
- }
175
- return (_jsx(NodeTimingRow, { timing: t, maxDurationMs: maxDurationMs, now: now }, `${t.agentRunId}-${t.phase}-${t.startedAt}`));
176
- })] }));
240
+ const outcome = getIterationOutcome(iteration);
241
+ return (_jsxs("div", { "data-testid": `iteration-${iteration.number}`, className: "border-border/50 bg-card/50 flex flex-col overflow-hidden rounded-lg border", children: [showHeader ? (_jsxs("div", { className: "bg-muted/30 border-border/50 flex items-center justify-between border-b px-3 py-1.5", children: [_jsxs("span", { className: "text-muted-foreground text-sm font-semibold tracking-wide", children: ["Iteration ", iteration.number] }), outcome ? (_jsxs("span", { className: `flex items-center gap-1 text-xs font-medium ${outcome.colorClass}`, children: [_jsx("span", { className: `inline-block h-1.5 w-1.5 rounded-full ${outcome.dotClass}` }), outcome.label] })) : null] })) : null, _jsxs("div", { className: "relative flex flex-col", children: [_jsx("div", { className: "bg-border/60 absolute top-4 bottom-4 left-[21.5px] w-px" }), iteration.timings.map((t, idx) => {
242
+ if (isLifecycleEvent(t.phase)) {
243
+ const isRejection = t.phase === 'run:rejected';
244
+ return (_jsx(LifecycleEventRow, { timing: t, message: isRejection ? iteration.rejectionMessage : undefined, attachments: isRejection ? iteration.rejectionAttachments : undefined, isFirst: idx === 0, isLast: idx === iteration.timings.length - 1 }, `${t.agentRunId}-${t.phase}-${t.startedAt}`));
245
+ }
246
+ return (_jsx(NodeTimingRow, { timing: t, maxDurationMs: maxDurationMs, now: now }, `${t.agentRunId}-${t.phase}-${t.startedAt}`));
247
+ })] })] }));
177
248
  }
178
249
  /* ---------------------------------------------------------------------------
179
250
  * Row components
180
251
  * ------------------------------------------------------------------------- */
181
- function LifecycleEventRow({ timing, message, attachments, }) {
252
+ function LifecycleEventRow({ timing, message, attachments, isFirst, isLast, }) {
182
253
  const event = LIFECYCLE_EVENTS[timing.phase];
183
254
  if (!event)
184
255
  return null;
185
256
  const hasAttachments = attachments && attachments.length > 0;
186
- return (_jsxs("div", { className: `text-xs ${event.colorClass}`, children: [_jsx("span", { children: event.label }), message ? (_jsxs("span", { "data-testid": "rejection-feedback-text", className: "text-muted-foreground ml-2 font-normal italic", children: ["\u2014 ", message] })) : null, hasAttachments ? (_jsx("div", { "data-testid": "rejection-feedback-attachments", className: "mt-1.5 ml-2", children: _jsx(InlineAttachments, { text: "", attachmentPaths: attachments }) })) : null] }));
257
+ const Icon = event.icon;
258
+ return (_jsxs("div", { className: `relative flex flex-col gap-1 px-3 ${isFirst ? 'pt-2' : 'pt-1'} ${isLast ? 'pb-2' : 'pb-1'}`, children: [_jsxs("div", { className: "flex items-center gap-2", children: [_jsx("div", { className: `relative z-10 flex h-5 w-5 shrink-0 items-center justify-center rounded-full ${event.bgClass}`, children: _jsx(Icon, { className: `h-3 w-3 ${event.colorClass}` }) }), _jsx("span", { className: `text-sm font-medium ${event.colorClass}`, children: event.label }), timing.startedAt &&
259
+ !(typeof timing.startedAt === 'string' && timing.startedAt.startsWith('synthetic')) ? (_jsx("span", { className: "text-muted-foreground/60 ml-auto text-xs tabular-nums", children: formatTimestamp(String(timing.startedAt)) })) : null] }), message ? (_jsxs("div", { className: "ml-[26px] flex items-start gap-1.5 rounded-md bg-orange-50/50 px-2 py-1.5 dark:bg-orange-950/20", children: [_jsx(MessageSquare, { className: "mt-0.5 h-3.5 w-3.5 shrink-0 text-orange-400" }), _jsxs("span", { "data-testid": "rejection-feedback-text", className: "text-muted-foreground text-xs leading-relaxed italic", children: ["\u2014 ", message] })] })) : null, hasAttachments ? (_jsx("div", { "data-testid": "rejection-feedback-attachments", className: "ml-[26px]", children: _jsx(InlineAttachments, { text: "", attachmentPaths: attachments }) })) : null] }));
187
260
  }
188
261
  function NodeTimingRow({ timing, maxDurationMs, now, }) {
189
262
  const suffix = timing.phase.includes(':') ? timing.phase.split(':')[1] : null;
190
263
  const isSubPhase = suffix !== null;
191
- // Distinguish implementation sub-phases (phase-1, phase-2) from rejection retries (2, 3)
192
264
  const isImplPhase = suffix?.startsWith('phase-') ?? false;
193
265
  const label = isImplPhase
194
266
  ? `Phase ${suffix.replace('phase-', '')}`
@@ -208,17 +280,21 @@ function NodeTimingRow({ timing, maxDurationMs, now, }) {
208
280
  const totalTokens = timing.inputTokens != null || timing.outputTokens != null
209
281
  ? (timing.inputTokens ?? 0) + (timing.outputTokens ?? 0)
210
282
  : null;
211
- return (_jsxs("div", { className: isSubPhase ? 'flex flex-col gap-1 pl-6' : 'flex flex-col gap-1', children: [_jsxs("div", { "data-testid": `timing-bar-${timing.phase}`, className: "flex items-center gap-2", children: [_jsx("span", { className: `text-muted-foreground shrink-0 text-xs ${isSubPhase ? 'w-18' : 'w-24'}`, children: label }), _jsx("div", { className: `bg-muted min-w-0 flex-1 overflow-hidden rounded-full ${isSubPhase ? 'h-2.5' : 'h-3'}`, children: _jsx("div", { className: `h-full rounded-full ${barColorClass}${isRunning ? 'animate-pulse' : ''}`, style: { width: `${Math.min(barPercent, 100)}%` } }) }), _jsx("span", { className: "text-muted-foreground w-10 shrink-0 text-right text-xs tabular-nums", children: formatDuration(durationMs) }), _jsx("span", { className: "text-muted-foreground w-12 shrink-0 text-right text-[10px] tabular-nums", children: totalTokens != null && totalTokens > 0 ? (_jsxs("span", { className: "inline-flex items-center gap-0.5", children: [_jsx(Zap, { className: "h-2 w-2 opacity-50" }), formatTokens(totalTokens)] })) : null })] }), timing.approvalWaitMs != null && timing.approvalWaitMs > 0 ? (_jsx(ApprovalWaitRow, { timing: timing, maxDurationMs: maxDurationMs })) : null] }));
283
+ return (_jsxs("div", { className: `relative flex flex-col gap-0.5 px-3 py-1.5 ${isSubPhase ? 'ml-4' : ''}`, children: [_jsxs("div", { "data-testid": `timing-bar-${timing.phase}`, className: "flex items-center gap-2", children: [_jsx("div", { className: "relative z-10 flex h-5 w-5 shrink-0 items-center justify-center", children: _jsx("div", { className: `rounded-full ${isRunning ? 'h-3 w-3 animate-pulse' : 'h-2.5 w-2.5'} ${isRunning
284
+ ? 'bg-blue-500'
285
+ : timing.completedAt
286
+ ? 'bg-emerald-500'
287
+ : 'bg-muted-foreground/30'}` }) }), _jsx("span", { className: `w-28 shrink-0 truncate text-sm font-medium ${isSubPhase ? 'text-muted-foreground' : 'text-foreground/80'}`, children: label }), _jsx("div", { className: `bg-muted min-w-0 flex-1 overflow-hidden rounded-full ${isSubPhase ? 'h-1.5' : 'h-2'}`, children: _jsx("div", { className: `h-full rounded-full transition-all duration-300 ${barColorClass}${isRunning ? 'animate-pulse' : ''}`, style: { width: `${Math.min(barPercent, 100)}%` } }) }), _jsx("span", { className: "text-muted-foreground w-14 shrink-0 text-right text-sm font-medium tabular-nums", children: formatDuration(durationMs) })] }), _jsxs("div", { className: "ml-[28px] flex items-center gap-3 text-xs", children: [timing.startedAt ? (_jsx("span", { className: "text-muted-foreground/60 tabular-nums", children: formatTimestamp(timing.startedAt) })) : null, totalTokens != null && totalTokens > 0 ? (_jsxs("span", { className: "text-muted-foreground/70 inline-flex items-center gap-0.5", children: [_jsx(Zap, { className: "h-3 w-3 opacity-50" }), formatTokens(totalTokens)] })) : null, timing.costUsd != null && timing.costUsd > 0 ? (_jsxs("span", { className: "text-muted-foreground/70 inline-flex items-center gap-0.5", children: [_jsx(DollarSign, { className: "h-3 w-3 opacity-50" }), formatCost(timing.costUsd)] })) : null] }), timing.approvalWaitMs != null && timing.approvalWaitMs > 0 ? (_jsx(ApprovalWaitRow, { timing: timing, maxDurationMs: maxDurationMs })) : null] }));
212
288
  }
213
289
  function ApprovalWaitRow({ timing, maxDurationMs, }) {
214
290
  const waitMs = timing.approvalWaitMs ?? 0;
215
291
  const barPercent = maxDurationMs > 0 ? Math.max(2, (waitMs / maxDurationMs) * 100) : 2;
216
- return (_jsxs("div", { "data-testid": `approval-wait-${timing.phase}`, className: "flex items-center gap-2 pl-4", children: [_jsx("span", { className: "text-muted-foreground w-20 shrink-0 text-xs", children: "approval" }), _jsx("div", { className: "bg-muted h-2.5 min-w-0 flex-1 overflow-hidden rounded-full", children: _jsx("div", { className: "h-full rounded-full bg-amber-500", style: { width: `${Math.min(barPercent, 100)}%` } }) }), _jsx("span", { className: "text-muted-foreground w-10 shrink-0 text-right text-xs tabular-nums", children: formatDuration(waitMs) }), _jsx("span", { className: "w-12 shrink-0" })] }));
292
+ return (_jsxs("div", { "data-testid": `approval-wait-${timing.phase}`, className: "ml-[26px] flex items-center gap-2 rounded-md bg-amber-50/50 px-1.5 py-1 dark:bg-amber-950/20", children: [_jsx(Timer, { className: "h-3.5 w-3.5 shrink-0 text-amber-500" }), _jsx("span", { className: "text-muted-foreground w-16 shrink-0 text-xs", children: "approval" }), _jsx("div", { className: "bg-muted h-1.5 min-w-0 flex-1 overflow-hidden rounded-full", children: _jsx("div", { className: "h-full rounded-full bg-amber-500", style: { width: `${Math.min(barPercent, 100)}%` } }) }), _jsx("span", { className: "text-muted-foreground w-14 shrink-0 text-right text-xs tabular-nums", children: formatDuration(waitMs) })] }));
217
293
  }
218
- function SummaryTotals({ totalExecMs, totalWaitMs, totalInputTokens, totalOutputTokens, }) {
294
+ function SummaryTotals({ totalExecMs, totalWaitMs, totalInputTokens, totalOutputTokens, totalCostUsd, }) {
219
295
  const totalTokens = totalInputTokens + totalOutputTokens;
220
- return (_jsxs("div", { "data-testid": "activity-summary", className: "border-border flex flex-col gap-1.5 border-t pt-3", children: [_jsx(SummaryRow, { label: "Total execution", value: formatDuration(totalExecMs) }), totalWaitMs > 0 ? (_jsxs(_Fragment, { children: [_jsx(SummaryRow, { label: "Total wait", value: formatDuration(totalWaitMs) }), _jsx(SummaryRow, { label: "Total wall-clock", value: formatDuration(totalExecMs + totalWaitMs) })] })) : null, totalTokens > 0 ? (_jsx(SummaryRow, { label: "Total tokens", value: `${formatTokens(totalTokens)} (${formatTokens(totalInputTokens)} in · ${formatTokens(totalOutputTokens)} out)` })) : null] }));
296
+ return (_jsxs("div", { "data-testid": "activity-summary", className: "border-border bg-card/30 flex flex-col gap-2 rounded-lg border p-3", children: [_jsx("div", { className: "text-muted-foreground mb-0.5 text-xs font-semibold tracking-wider uppercase", children: "Summary" }), _jsxs("div", { className: "grid grid-cols-2 gap-x-4 gap-y-2", children: [_jsx(SummaryItem, { icon: Clock, label: "Total execution", value: formatDuration(totalExecMs) }), totalWaitMs > 0 ? (_jsxs(_Fragment, { children: [_jsx(SummaryItem, { icon: Timer, label: "Total wait", value: formatDuration(totalWaitMs) }), _jsx(SummaryItem, { icon: Clock, label: "Total wall-clock", value: formatDuration(totalExecMs + totalWaitMs), className: "col-span-2" })] })) : null, totalTokens > 0 ? (_jsx(SummaryItem, { icon: Zap, label: "Total tokens", value: `${formatTokens(totalTokens)} (${formatTokens(totalInputTokens)} in · ${formatTokens(totalOutputTokens)} out)`, className: "col-span-2" })) : null, totalCostUsd > 0 ? (_jsx(SummaryItem, { icon: DollarSign, label: "Total cost", value: formatCost(totalCostUsd) })) : null] })] }));
221
297
  }
222
- function SummaryRow({ label, value }) {
223
- return (_jsxs("div", { className: "flex items-center justify-between", children: [_jsx("span", { className: "text-muted-foreground text-xs font-medium", children: label }), _jsx("span", { className: "text-xs font-medium", children: value })] }));
298
+ function SummaryItem({ icon: Icon, label, value, className = '', }) {
299
+ return (_jsxs("div", { className: `flex items-center justify-between ${className}`, children: [_jsxs("span", { className: "text-muted-foreground flex items-center gap-1.5 text-sm", children: [_jsx(Icon, { className: "h-3.5 w-3.5 opacity-50" }), _jsx("span", { className: "font-medium", children: label })] }), _jsx("span", { className: "text-sm font-semibold tabular-nums", children: value })] }));
224
300
  }
@@ -1 +1 @@
1
- {"version":3,"file":"activity-tab.stories.d.ts","sourceRoot":"","sources":["../../../../../../../src/presentation/web/components/common/feature-drawer-tabs/activity-tab.stories.tsx"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,IAAI,EAAE,QAAQ,EAAE,MAAM,kBAAkB,CAAC;AACvD,OAAO,EAAE,WAAW,EAAE,MAAM,gBAAgB,CAAC;AAG7C,QAAA,MAAM,IAAI,EAAE,IAAI,CAAC,OAAO,WAAW,CAclC,CAAC;AAEF,eAAe,IAAI,CAAC;AACpB,KAAK,KAAK,GAAG,QAAQ,CAAC,OAAO,WAAW,CAAC,CAAC;AAmK1C,2EAA2E;AAC3E,eAAO,MAAM,OAAO,EAAE,KAMrB,CAAC;AAEF,uDAAuD;AACvD,eAAO,MAAM,YAAY,EAAE,KAM1B,CAAC;AAEF,kEAAkE;AAClE,eAAO,MAAM,YAAY,EAAE,KAM1B,CAAC;AAEF,qEAAqE;AACrE,eAAO,MAAM,OAAO,EAAE,KAMrB,CAAC;AAEF,8CAA8C;AAC9C,eAAO,MAAM,KAAK,EAAE,KAMnB,CAAC;AAEF,0CAA0C;AAC1C,eAAO,MAAM,KAAK,EAAE,KAMnB,CAAC;AAEF,0EAA0E;AAC1E,eAAO,MAAM,aAAa,EAAE,KAsE3B,CAAC;AAEF;;;;;;GAMG;AACH,eAAO,MAAM,kBAAkB,EAAE,KAwEhC,CAAC;AAEF,qEAAqE;AACrE,eAAO,MAAM,iBAAiB,EAAE,KAgC/B,CAAC;AAEF;;;GAGG;AACH,eAAO,MAAM,aAAa,EAAE,KAiI3B,CAAC"}
1
+ {"version":3,"file":"activity-tab.stories.d.ts","sourceRoot":"","sources":["../../../../../../../src/presentation/web/components/common/feature-drawer-tabs/activity-tab.stories.tsx"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,IAAI,EAAE,QAAQ,EAAE,MAAM,kBAAkB,CAAC;AACvD,OAAO,EAAE,WAAW,EAAE,MAAM,gBAAgB,CAAC;AAG7C,QAAA,MAAM,IAAI,EAAE,IAAI,CAAC,OAAO,WAAW,CAclC,CAAC;AAEF,eAAe,IAAI,CAAC;AACpB,KAAK,KAAK,GAAG,QAAQ,CAAC,OAAO,WAAW,CAAC,CAAC;AAsM1C,2EAA2E;AAC3E,eAAO,MAAM,OAAO,EAAE,KAMrB,CAAC;AAEF,uDAAuD;AACvD,eAAO,MAAM,YAAY,EAAE,KAM1B,CAAC;AAEF,kEAAkE;AAClE,eAAO,MAAM,YAAY,EAAE,KAM1B,CAAC;AAEF,qEAAqE;AACrE,eAAO,MAAM,OAAO,EAAE,KAMrB,CAAC;AAEF,8CAA8C;AAC9C,eAAO,MAAM,KAAK,EAAE,KAMnB,CAAC;AAEF,0CAA0C;AAC1C,eAAO,MAAM,KAAK,EAAE,KAMnB,CAAC;AAEF,0EAA0E;AAC1E,eAAO,MAAM,aAAa,EAAE,KAsE3B,CAAC;AAEF;;;;;;GAMG;AACH,eAAO,MAAM,kBAAkB,EAAE,KAwEhC,CAAC;AAEF,qEAAqE;AACrE,eAAO,MAAM,iBAAiB,EAAE,KAgC/B,CAAC;AAEF;;;GAGG;AACH,eAAO,MAAM,aAAa,EAAE,KAiI3B,CAAC"}
@@ -29,6 +29,13 @@ const singleRunTimings = [
29
29
  startedAt: '2025-01-15T10:00:01Z',
30
30
  completedAt: '2025-01-15T10:00:15Z',
31
31
  durationMs: 14000,
32
+ inputTokens: 28500,
33
+ outputTokens: 3200,
34
+ cacheCreationInputTokens: 22000,
35
+ cacheReadInputTokens: 0,
36
+ costUsd: 0.1245,
37
+ numTurns: 2,
38
+ durationApiMs: 8400,
32
39
  },
33
40
  {
34
41
  agentRunId: 'run-1',
@@ -38,6 +45,13 @@ const singleRunTimings = [
38
45
  durationMs: 90000,
39
46
  waitingApprovalAt: '2025-01-15T10:01:00Z',
40
47
  approvalWaitMs: 30000,
48
+ inputTokens: 45200,
49
+ outputTokens: 8100,
50
+ cacheCreationInputTokens: 12000,
51
+ cacheReadInputTokens: 22000,
52
+ costUsd: 0.2831,
53
+ numTurns: 5,
54
+ durationApiMs: 42000,
41
55
  },
42
56
  {
43
57
  agentRunId: 'run-1',
@@ -45,6 +59,13 @@ const singleRunTimings = [
45
59
  startedAt: '2025-01-15T10:01:45Z',
46
60
  completedAt: '2025-01-15T10:03:30Z',
47
61
  durationMs: 105000,
62
+ inputTokens: 92400,
63
+ outputTokens: 15600,
64
+ cacheCreationInputTokens: 8000,
65
+ cacheReadInputTokens: 34000,
66
+ costUsd: 0.5127,
67
+ numTurns: 8,
68
+ durationApiMs: 78000,
48
69
  },
49
70
  {
50
71
  agentRunId: 'run-1',
@@ -54,6 +75,13 @@ const singleRunTimings = [
54
75
  durationMs: 90000,
55
76
  waitingApprovalAt: '2025-01-15T10:04:30Z',
56
77
  approvalWaitMs: 15000,
78
+ inputTokens: 68300,
79
+ outputTokens: 12400,
80
+ cacheCreationInputTokens: 5000,
81
+ cacheReadInputTokens: 34000,
82
+ costUsd: 0.3892,
83
+ numTurns: 6,
84
+ durationApiMs: 55000,
57
85
  },
58
86
  {
59
87
  agentRunId: 'run-1',
@@ -61,6 +89,13 @@ const singleRunTimings = [
61
89
  startedAt: '2025-01-15T10:05:00Z',
62
90
  completedAt: '2025-01-15T10:15:00Z',
63
91
  durationMs: 600000,
92
+ inputTokens: 485000,
93
+ outputTokens: 128000,
94
+ cacheCreationInputTokens: 45000,
95
+ cacheReadInputTokens: 34000,
96
+ costUsd: 3.2451,
97
+ numTurns: 42,
98
+ durationApiMs: 385000,
64
99
  },
65
100
  {
66
101
  agentRunId: 'run-1',
@@ -1 +1 @@
1
- {"version":3,"file":"overview-tab.d.ts","sourceRoot":"","sources":["../../../../../../../src/presentation/web/components/common/feature-drawer-tabs/overview-tab.tsx"],"names":[],"mappings":"AAuBA,OAAO,KAAK,EAAE,eAAe,EAAE,MAAM,kCAAkC,CAAC;AAQxE,MAAM,WAAW,gBAAgB;IAC/B,IAAI,EAAE,eAAe,CAAC;CACvB;AAED,wBAAgB,WAAW,CAAC,EAAE,IAAI,EAAE,EAAE,gBAAgB,2CAqDrD"}
1
+ {"version":3,"file":"overview-tab.d.ts","sourceRoot":"","sources":["../../../../../../../src/presentation/web/components/common/feature-drawer-tabs/overview-tab.tsx"],"names":[],"mappings":"AAwBA,OAAO,KAAK,EAAE,eAAe,EAAE,MAAM,kCAAkC,CAAC;AAQxE,MAAM,WAAW,gBAAgB;IAC/B,IAAI,EAAE,eAAe,CAAC;CACvB;AAED,wBAAgB,WAAW,CAAC,EAAE,IAAI,EAAE,EAAE,gBAAgB,2CA+DrD"}
@@ -1,7 +1,7 @@
1
1
  'use client';
2
2
  import { jsx as _jsx, jsxs as _jsxs, Fragment as _Fragment } from "react/jsx-runtime";
3
3
  import { useState, useEffect, useRef } from 'react';
4
- import { AlertTriangle, Check, ExternalLink, FileSearch, GitBranch, GitCommitHorizontal, RotateCcw, ShieldCheck, X, Zap, } from 'lucide-react';
4
+ import { AlertTriangle, Check, ExternalLink, FileSearch, GitBranch, GitCommitHorizontal, RotateCcw, ShieldCheck, Square, X, Zap, } from 'lucide-react';
5
5
  import { InlineAttachments } from '../../common/inline-attachments/index.js';
6
6
  import { PrStatus } from '../../../../../../packages/core/src/domain/generated/output.js';
7
7
  import { cn } from '../../../lib/utils.js';
@@ -15,7 +15,7 @@ import { getModelMeta } from '../../../lib/model-metadata.js';
15
15
  import { formatDuration } from '../../../lib/format-duration.js';
16
16
  export function OverviewTab({ data }) {
17
17
  const isCompleted = data.lifecycle === 'maintain';
18
- return (_jsxs(_Fragment, { children: [_jsxs("div", { "data-testid": "feature-drawer-status", className: "flex flex-col gap-3 p-4", children: [_jsx("div", { className: "text-muted-foreground text-xs font-semibold tracking-wider", children: lifecycleDisplayLabels[data.lifecycle] }), _jsxs("div", { className: "flex items-center gap-2", children: [_jsx(FeatureStateBadge, { data: data }), data.state === 'error' && data.onRetry ? (_jsxs("button", { "data-testid": "feature-drawer-retry-button", onClick: () => data.onRetry(data.featureId), className: "flex shrink-0 cursor-pointer items-center gap-1.5 rounded-full bg-red-50 px-3 py-1.5 text-sm font-medium text-red-700 transition-colors hover:bg-red-100", children: [_jsx(RotateCcw, { className: "h-3.5 w-3.5" }), "Retry"] })) : null] }), !isCompleted && data.progress > 0 ? (_jsxs("div", { "data-testid": "feature-drawer-progress", className: "flex flex-col gap-1", children: [_jsxs("div", { className: "text-muted-foreground flex items-center justify-between text-xs", children: [_jsx("span", { children: "Progress" }), _jsxs("span", { children: [data.progress, "%"] })] }), _jsx("div", { className: "bg-muted h-2 w-full overflow-hidden rounded-full", children: _jsx("div", { className: cn('h-full rounded-full transition-all', featureNodeStateConfig[data.state].progressClass), style: { width: `${data.progress}%` } }) })] })) : null, isCompleted && data.pr ? _jsx(FeaturePrInfo, { pr: data.pr }) : null] }), _jsx(FeatureInfo, { data: data }), !isCompleted && data.pr ? (_jsxs(_Fragment, { children: [_jsx(Separator, {}), _jsx("div", { className: "p-4", children: _jsx(FeaturePrInfo, { pr: data.pr }) })] })) : null, _jsx(FeatureDetails, { data: data }), _jsx(FeatureSettings, { data: data })] }));
18
+ return (_jsxs(_Fragment, { children: [_jsxs("div", { "data-testid": "feature-drawer-status", className: "flex flex-col gap-3 p-4", children: [_jsx("div", { className: "text-muted-foreground text-xs font-semibold tracking-wider", children: lifecycleDisplayLabels[data.lifecycle] }), _jsxs("div", { className: "flex items-center gap-2", children: [_jsx(FeatureStateBadge, { data: data }), data.state === 'error' && data.onRetry ? (_jsxs("button", { "data-testid": "feature-drawer-retry-button", onClick: () => data.onRetry(data.featureId), className: "flex shrink-0 cursor-pointer items-center gap-1.5 rounded-full bg-red-50 px-3 py-1.5 text-sm font-medium text-red-700 transition-colors hover:bg-red-100", children: [_jsx(RotateCcw, { className: "h-3.5 w-3.5" }), "Retry"] })) : null, (data.state === 'running' || data.state === 'action-required') && data.onStop ? (_jsxs("button", { "data-testid": "feature-drawer-stop-button", onClick: () => data.onStop(data.featureId), className: "flex shrink-0 cursor-pointer items-center gap-1.5 rounded-full bg-red-50 px-3 py-1.5 text-sm font-medium text-red-700 transition-colors hover:bg-red-100", children: [_jsx(Square, { className: "h-3.5 w-3.5" }), "Stop"] })) : null] }), !isCompleted && data.progress > 0 ? (_jsxs("div", { "data-testid": "feature-drawer-progress", className: "flex flex-col gap-1", children: [_jsxs("div", { className: "text-muted-foreground flex items-center justify-between text-xs", children: [_jsx("span", { children: "Progress" }), _jsxs("span", { children: [data.progress, "%"] })] }), _jsx("div", { className: "bg-muted h-2 w-full overflow-hidden rounded-full", children: _jsx("div", { className: cn('h-full rounded-full transition-all', featureNodeStateConfig[data.state].progressClass), style: { width: `${data.progress}%` } }) })] })) : null, isCompleted && data.pr ? _jsx(FeaturePrInfo, { pr: data.pr }) : null] }), _jsx(FeatureInfo, { data: data }), !isCompleted && data.pr ? (_jsxs(_Fragment, { children: [_jsx(Separator, {}), _jsx("div", { className: "p-4", children: _jsx(FeaturePrInfo, { pr: data.pr }) })] })) : null, _jsx(FeatureDetails, { data: data }), _jsx(FeatureSettings, { data: data })] }));
19
19
  }
20
20
  function FeatureStateBadge({ data }) {
21
21
  const config = featureNodeStateConfig[data.state];
@@ -17,6 +17,8 @@ export declare const Blocked: Story;
17
17
  export declare const Error: Story;
18
18
  /** Error state with retry button visible. */
19
19
  export declare const ErrorWithRetry: Story;
20
+ /** Running state with stop button visible. */
21
+ export declare const RunningWithStop: Story;
20
22
  /** Minimal data — only required fields, no optional details or PR. */
21
23
  export declare const Minimal: Story;
22
24
  /** Fast mode feature — shows lightning icon in details section. */
@@ -1 +1 @@
1
- {"version":3,"file":"overview-tab.stories.d.ts","sourceRoot":"","sources":["../../../../../../../src/presentation/web/components/common/feature-drawer-tabs/overview-tab.stories.tsx"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,IAAI,EAAE,QAAQ,EAAE,MAAM,kBAAkB,CAAC;AAGvD,OAAO,EAAE,WAAW,EAAE,MAAM,gBAAgB,CAAC;AAG7C,QAAA,MAAM,IAAI,EAAE,IAAI,CAAC,OAAO,WAAW,CAclC,CAAC;AAEF,eAAe,IAAI,CAAC;AACpB,KAAK,KAAK,GAAG,QAAQ,CAAC,OAAO,WAAW,CAAC,CAAC;AA0G1C,uEAAuE;AACvE,eAAO,MAAM,OAAO,EAAE,KAErB,CAAC;AAEF,8CAA8C;AAC9C,eAAO,MAAM,IAAI,EAAE,KAElB,CAAC;AAEF,yDAAyD;AACzD,eAAO,MAAM,UAAU,EAAE,KAExB,CAAC;AAEF,wDAAwD;AACxD,eAAO,MAAM,gBAAgB,EAAE,KAE9B,CAAC;AAEF,iDAAiD;AACjD,eAAO,MAAM,OAAO,EAAE,KAErB,CAAC;AAEF,gDAAgD;AAChD,eAAO,MAAM,KAAK,EAAE,KAEnB,CAAC;AAOF,6CAA6C;AAC7C,eAAO,MAAM,cAAc,EAAE,KAE5B,CAAC;AAEF,sEAAsE;AACtE,eAAO,MAAM,OAAO,EAAE,KAErB,CAAC;AAwBF,mEAAmE;AACnE,eAAO,MAAM,QAAQ,EAAE,KAEtB,CAAC;AAMF,0BAA0B;AAC1B,eAAO,MAAM,iBAAiB,EAAE,KAE/B,CAAC;AAEF,sBAAsB;AACtB,eAAO,MAAM,aAAa,EAAE,KAE3B,CAAC;AAEF,oBAAoB;AACpB,eAAO,MAAM,WAAW,EAAE,KAEzB,CAAC;AAEF,sBAAsB;AACtB,eAAO,MAAM,aAAa,EAAE,KAE3B,CAAC;AAEF,gEAAgE;AAChE,eAAO,MAAM,oBAAoB,EAAE,KAclC,CAAC;AAqBF,4DAA4D;AAC5D,eAAO,MAAM,sBAAsB,EAAE,KAEpC,CAAC;AAEF,sDAAsD;AACtD,eAAO,MAAM,gBAAgB,EAAE,KAO9B,CAAC;AAEF,+FAA+F;AAC/F,eAAO,MAAM,eAAe,EAAE,KAgB7B,CAAC;AAMF,oFAAoF;AACpF,eAAO,MAAM,eAAe,EAAE,KAY7B,CAAC;AAEF,kDAAkD;AAClD,eAAO,MAAM,uBAAuB,EAAE,KAYrC,CAAC;AAEF,mDAAmD;AACnD,eAAO,MAAM,uBAAuB,EAAE,KAYrC,CAAC;AAEF,2CAA2C;AAC3C,eAAO,MAAM,oBAAoB,EAAE,KAYlC,CAAC;AAEF,+DAA+D;AAC/D,eAAO,MAAM,mBAAmB,EAAE,KAQjC,CAAC"}
1
+ {"version":3,"file":"overview-tab.stories.d.ts","sourceRoot":"","sources":["../../../../../../../src/presentation/web/components/common/feature-drawer-tabs/overview-tab.stories.tsx"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,IAAI,EAAE,QAAQ,EAAE,MAAM,kBAAkB,CAAC;AAGvD,OAAO,EAAE,WAAW,EAAE,MAAM,gBAAgB,CAAC;AAG7C,QAAA,MAAM,IAAI,EAAE,IAAI,CAAC,OAAO,WAAW,CAclC,CAAC;AAEF,eAAe,IAAI,CAAC;AACpB,KAAK,KAAK,GAAG,QAAQ,CAAC,OAAO,WAAW,CAAC,CAAC;AA0G1C,uEAAuE;AACvE,eAAO,MAAM,OAAO,EAAE,KAErB,CAAC;AAEF,8CAA8C;AAC9C,eAAO,MAAM,IAAI,EAAE,KAElB,CAAC;AAEF,yDAAyD;AACzD,eAAO,MAAM,UAAU,EAAE,KAExB,CAAC;AAEF,wDAAwD;AACxD,eAAO,MAAM,gBAAgB,EAAE,KAE9B,CAAC;AAEF,iDAAiD;AACjD,eAAO,MAAM,OAAO,EAAE,KAErB,CAAC;AAEF,gDAAgD;AAChD,eAAO,MAAM,KAAK,EAAE,KAEnB,CAAC;AAOF,6CAA6C;AAC7C,eAAO,MAAM,cAAc,EAAE,KAE5B,CAAC;AAEF,8CAA8C;AAC9C,eAAO,MAAM,eAAe,EAAE,KAE7B,CAAC;AAEF,sEAAsE;AACtE,eAAO,MAAM,OAAO,EAAE,KAErB,CAAC;AAwBF,mEAAmE;AACnE,eAAO,MAAM,QAAQ,EAAE,KAEtB,CAAC;AAMF,0BAA0B;AAC1B,eAAO,MAAM,iBAAiB,EAAE,KAE/B,CAAC;AAEF,sBAAsB;AACtB,eAAO,MAAM,aAAa,EAAE,KAE3B,CAAC;AAEF,oBAAoB;AACpB,eAAO,MAAM,WAAW,EAAE,KAEzB,CAAC;AAEF,sBAAsB;AACtB,eAAO,MAAM,aAAa,EAAE,KAE3B,CAAC;AAEF,gEAAgE;AAChE,eAAO,MAAM,oBAAoB,EAAE,KAclC,CAAC;AAqBF,4DAA4D;AAC5D,eAAO,MAAM,sBAAsB,EAAE,KAEpC,CAAC;AAEF,sDAAsD;AACtD,eAAO,MAAM,gBAAgB,EAAE,KAO9B,CAAC;AAEF,+FAA+F;AAC/F,eAAO,MAAM,eAAe,EAAE,KAgB7B,CAAC;AAMF,oFAAoF;AACpF,eAAO,MAAM,eAAe,EAAE,KAY7B,CAAC;AAEF,kDAAkD;AAClD,eAAO,MAAM,uBAAuB,EAAE,KAYrC,CAAC;AAEF,mDAAmD;AACnD,eAAO,MAAM,uBAAuB,EAAE,KAYrC,CAAC;AAEF,2CAA2C;AAC3C,eAAO,MAAM,oBAAoB,EAAE,KAYlC,CAAC;AAEF,+DAA+D;AAC/D,eAAO,MAAM,mBAAmB,EAAE,KAQjC,CAAC"}
@@ -141,6 +141,10 @@ const errorWithRetryData = {
141
141
  export const ErrorWithRetry = {
142
142
  args: { data: errorWithRetryData },
143
143
  };
144
+ /** Running state with stop button visible. */
145
+ export const RunningWithStop = {
146
+ args: { data: { ...fullData, onStop: fn() } },
147
+ };
144
148
  /** Minimal data — only required fields, no optional details or PR. */
145
149
  export const Minimal = {
146
150
  args: { data: minimalData },
@@ -90,6 +90,7 @@ export interface FeatureNodeData {
90
90
  onDelete?: (featureId: string, cleanup?: boolean, cascadeDelete?: boolean) => void;
91
91
  onRetry?: (featureId: string) => void;
92
92
  onStart?: (featureId: string) => void;
93
+ onStop?: (featureId: string) => void;
93
94
  showHandles?: boolean;
94
95
  }
95
96
  export type FeatureNodeType = Node<FeatureNodeData, 'featureNode'>;