@shepai/cli 1.103.1-pr308.436876d → 1.103.1-pr309.f0bca17

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 (164) hide show
  1. package/dist/src/presentation/web/components/common/control-center-drawer/feature-drawer-client.d.ts.map +1 -1
  2. package/dist/src/presentation/web/components/common/control-center-drawer/feature-drawer-client.js +1 -1
  3. package/dist/src/presentation/web/components/common/feature-drawer-tabs/activity-tab.d.ts.map +1 -1
  4. package/dist/src/presentation/web/components/common/feature-drawer-tabs/activity-tab.js +50 -8
  5. package/dist/src/presentation/web/components/common/feature-drawer-tabs/event-log-viewer.d.ts +5 -0
  6. package/dist/src/presentation/web/components/common/feature-drawer-tabs/event-log-viewer.d.ts.map +1 -0
  7. package/dist/src/presentation/web/components/common/feature-drawer-tabs/event-log-viewer.js +113 -0
  8. package/dist/src/presentation/web/components/common/feature-drawer-tabs/event-log-viewer.stories.d.ts +18 -0
  9. package/dist/src/presentation/web/components/common/feature-drawer-tabs/event-log-viewer.stories.d.ts.map +1 -0
  10. package/dist/src/presentation/web/components/common/feature-drawer-tabs/event-log-viewer.stories.js +88 -0
  11. package/dist/src/presentation/web/components/common/feature-drawer-tabs/feature-drawer-tabs.d.ts +4 -1
  12. package/dist/src/presentation/web/components/common/feature-drawer-tabs/feature-drawer-tabs.d.ts.map +1 -1
  13. package/dist/src/presentation/web/components/common/feature-drawer-tabs/feature-drawer-tabs.js +31 -11
  14. package/dist/src/presentation/web/components/common/feature-drawer-tabs/log-tab.d.ts.map +1 -1
  15. package/dist/src/presentation/web/components/common/feature-drawer-tabs/log-tab.js +10 -2
  16. package/dist/src/presentation/web/components/common/feature-drawer-tabs/log-tab.stories.d.ts +5 -3
  17. package/dist/src/presentation/web/components/common/feature-drawer-tabs/log-tab.stories.d.ts.map +1 -1
  18. package/dist/src/presentation/web/components/common/feature-drawer-tabs/log-tab.stories.js +92 -9
  19. package/dist/src/presentation/web/components/common/feature-drawer-tabs/overview-tab.d.ts.map +1 -1
  20. package/dist/src/presentation/web/components/common/feature-drawer-tabs/overview-tab.js +35 -2
  21. package/dist/src/presentation/web/lib/parse-log-line.d.ts +49 -0
  22. package/dist/src/presentation/web/lib/parse-log-line.d.ts.map +1 -0
  23. package/dist/src/presentation/web/lib/parse-log-line.js +126 -0
  24. package/dist/tsconfig.build.tsbuildinfo +1 -1
  25. package/package.json +1 -1
  26. package/web/.next/BUILD_ID +1 -1
  27. package/web/.next/build-manifest.json +2 -2
  28. package/web/.next/fallback-build-manifest.json +2 -2
  29. package/web/.next/prerender-manifest.json +3 -3
  30. package/web/.next/required-server-files.js +1 -1
  31. package/web/.next/required-server-files.json +1 -1
  32. package/web/.next/server/app/(dashboard)/@drawer/create/page/server-reference-manifest.json +20 -20
  33. package/web/.next/server/app/(dashboard)/@drawer/create/page.js.nft.json +1 -1
  34. package/web/.next/server/app/(dashboard)/@drawer/create/page_client-reference-manifest.js +1 -1
  35. package/web/.next/server/app/(dashboard)/@drawer/feature/[featureId]/[tab]/page/server-reference-manifest.json +25 -25
  36. package/web/.next/server/app/(dashboard)/@drawer/feature/[featureId]/[tab]/page.js.nft.json +1 -1
  37. package/web/.next/server/app/(dashboard)/@drawer/feature/[featureId]/[tab]/page_client-reference-manifest.js +1 -1
  38. package/web/.next/server/app/(dashboard)/@drawer/feature/[featureId]/page/server-reference-manifest.json +25 -25
  39. package/web/.next/server/app/(dashboard)/@drawer/feature/[featureId]/page.js.nft.json +1 -1
  40. package/web/.next/server/app/(dashboard)/@drawer/feature/[featureId]/page_client-reference-manifest.js +1 -1
  41. package/web/.next/server/app/(dashboard)/@drawer/repository/[repositoryId]/page/server-reference-manifest.json +18 -18
  42. package/web/.next/server/app/(dashboard)/@drawer/repository/[repositoryId]/page.js.nft.json +1 -1
  43. package/web/.next/server/app/(dashboard)/@drawer/repository/[repositoryId]/page_client-reference-manifest.js +1 -1
  44. package/web/.next/server/app/(dashboard)/create/page/server-reference-manifest.json +20 -20
  45. package/web/.next/server/app/(dashboard)/create/page.js.nft.json +1 -1
  46. package/web/.next/server/app/(dashboard)/create/page_client-reference-manifest.js +1 -1
  47. package/web/.next/server/app/(dashboard)/feature/[featureId]/[tab]/page/server-reference-manifest.json +25 -25
  48. package/web/.next/server/app/(dashboard)/feature/[featureId]/[tab]/page.js.nft.json +1 -1
  49. package/web/.next/server/app/(dashboard)/feature/[featureId]/[tab]/page_client-reference-manifest.js +1 -1
  50. package/web/.next/server/app/(dashboard)/feature/[featureId]/page/server-reference-manifest.json +25 -25
  51. package/web/.next/server/app/(dashboard)/feature/[featureId]/page.js.nft.json +1 -1
  52. package/web/.next/server/app/(dashboard)/feature/[featureId]/page_client-reference-manifest.js +1 -1
  53. package/web/.next/server/app/(dashboard)/page/server-reference-manifest.json +18 -18
  54. package/web/.next/server/app/(dashboard)/page.js.nft.json +1 -1
  55. package/web/.next/server/app/(dashboard)/page_client-reference-manifest.js +1 -1
  56. package/web/.next/server/app/(dashboard)/repository/[repositoryId]/page/server-reference-manifest.json +18 -18
  57. package/web/.next/server/app/(dashboard)/repository/[repositoryId]/page.js.nft.json +1 -1
  58. package/web/.next/server/app/(dashboard)/repository/[repositoryId]/page_client-reference-manifest.js +1 -1
  59. package/web/.next/server/app/_global-error.html +2 -2
  60. package/web/.next/server/app/_global-error.rsc +1 -1
  61. package/web/.next/server/app/_global-error.segments/__PAGE__.segment.rsc +1 -1
  62. package/web/.next/server/app/_global-error.segments/_full.segment.rsc +1 -1
  63. package/web/.next/server/app/_global-error.segments/_head.segment.rsc +1 -1
  64. package/web/.next/server/app/_global-error.segments/_index.segment.rsc +1 -1
  65. package/web/.next/server/app/_global-error.segments/_tree.segment.rsc +1 -1
  66. package/web/.next/server/app/_not-found/page/server-reference-manifest.json +1 -1
  67. package/web/.next/server/app/_not-found/page_client-reference-manifest.js +1 -1
  68. package/web/.next/server/app/api/attachments/preview/route.js.nft.json +1 -1
  69. package/web/.next/server/app/api/cli-upgrade/route.js +2 -2
  70. package/web/.next/server/app/api/evidence/route.js.nft.json +1 -1
  71. package/web/.next/server/app/settings/page/server-reference-manifest.json +5 -5
  72. package/web/.next/server/app/settings/page.js.nft.json +1 -1
  73. package/web/.next/server/app/settings/page_client-reference-manifest.js +1 -1
  74. package/web/.next/server/app/skills/page/server-reference-manifest.json +6 -6
  75. package/web/.next/server/app/skills/page.js.nft.json +1 -1
  76. package/web/.next/server/app/skills/page_client-reference-manifest.js +1 -1
  77. package/web/.next/server/app/tools/page/server-reference-manifest.json +6 -6
  78. package/web/.next/server/app/tools/page.js.nft.json +1 -1
  79. package/web/.next/server/app/tools/page_client-reference-manifest.js +1 -1
  80. package/web/.next/server/app/version/page/server-reference-manifest.json +1 -1
  81. package/web/.next/server/app/version/page_client-reference-manifest.js +1 -1
  82. package/web/.next/server/chunks/[root-of-the-server]__d2c18946._.js +2 -2
  83. package/web/.next/server/chunks/[root-of-the-server]__f47bb8a5._.js +1 -1
  84. package/web/.next/server/chunks/ssr/744ca_web_components_common_control-center-drawer_create-drawer-client_tsx_5e26fc0a._.js +1 -1
  85. package/web/.next/server/chunks/ssr/744ca_web_components_common_control-center-drawer_create-drawer-client_tsx_5e26fc0a._.js.map +1 -1
  86. package/web/.next/server/chunks/ssr/8ba4b_server_app_(dashboard)_@drawer_repository_[repositoryId]_page_actions_0a7546ed.js +1 -1
  87. package/web/.next/server/chunks/ssr/8ba4b_server_app_(dashboard)_@drawer_repository_[repositoryId]_page_actions_0a7546ed.js.map +1 -1
  88. package/web/.next/server/chunks/ssr/8ba4b_server_app_(dashboard)_repository_[repositoryId]_page_actions_978cbb4c.js +1 -1
  89. package/web/.next/server/chunks/ssr/8ba4b_server_app_(dashboard)_repository_[repositoryId]_page_actions_978cbb4c.js.map +1 -1
  90. package/web/.next/server/chunks/ssr/[root-of-the-server]__11033878._.js +1 -1
  91. package/web/.next/server/chunks/ssr/[root-of-the-server]__11033878._.js.map +1 -1
  92. package/web/.next/server/chunks/ssr/[root-of-the-server]__24dd0927._.js +2 -2
  93. package/web/.next/server/chunks/ssr/[root-of-the-server]__357d99f9._.js +1 -1
  94. package/web/.next/server/chunks/ssr/[root-of-the-server]__51fc98b0._.js +1 -1
  95. package/web/.next/server/chunks/ssr/[root-of-the-server]__51fc98b0._.js.map +1 -1
  96. package/web/.next/server/chunks/ssr/[root-of-the-server]__57f37786._.js +1 -1
  97. package/web/.next/server/chunks/ssr/[root-of-the-server]__57f37786._.js.map +1 -1
  98. package/web/.next/server/chunks/ssr/[root-of-the-server]__5d87af2e._.js +1 -1
  99. package/web/.next/server/chunks/ssr/[root-of-the-server]__708dcad1._.js +1 -1
  100. package/web/.next/server/chunks/ssr/[root-of-the-server]__708dcad1._.js.map +1 -1
  101. package/web/.next/server/chunks/ssr/[root-of-the-server]__845a9d2a._.js +1 -1
  102. package/web/.next/server/chunks/ssr/[root-of-the-server]__845a9d2a._.js.map +1 -1
  103. package/web/.next/server/chunks/ssr/[root-of-the-server]__89e8a5cc._.js +2 -2
  104. package/web/.next/server/chunks/ssr/[root-of-the-server]__8e002910._.js +1 -1
  105. package/web/.next/server/chunks/ssr/[root-of-the-server]__8e002910._.js.map +1 -1
  106. package/web/.next/server/chunks/ssr/[root-of-the-server]__aad040c0._.js +2 -2
  107. package/web/.next/server/chunks/ssr/[root-of-the-server]__aad040c0._.js.map +1 -1
  108. package/web/.next/server/chunks/ssr/[root-of-the-server]__b1e68e34._.js +3 -0
  109. package/web/.next/server/chunks/ssr/{[root-of-the-server]__d91fdd51._.js.map → [root-of-the-server]__b1e68e34._.js.map} +1 -1
  110. package/web/.next/server/chunks/ssr/[root-of-the-server]__fdc75809._.js +1 -1
  111. package/web/.next/server/chunks/ssr/[root-of-the-server]__fdc75809._.js.map +1 -1
  112. package/web/.next/server/chunks/ssr/_135edb9c._.js +1 -1
  113. package/web/.next/server/chunks/ssr/_135edb9c._.js.map +1 -1
  114. package/web/.next/server/chunks/ssr/{_afa40e06._.js → _299324d0._.js} +2 -2
  115. package/web/.next/server/chunks/ssr/{_afa40e06._.js.map → _299324d0._.js.map} +1 -1
  116. package/web/.next/server/chunks/ssr/{_a09fb04a._.js → _601a084c._.js} +2 -2
  117. package/web/.next/server/chunks/ssr/{_a09fb04a._.js.map → _601a084c._.js.map} +1 -1
  118. package/web/.next/server/chunks/ssr/_8dacd1e7._.js +1 -1
  119. package/web/.next/server/chunks/ssr/_8dacd1e7._.js.map +1 -1
  120. package/web/.next/server/chunks/ssr/{_baab52a9._.js → _c205e198._.js} +2 -2
  121. package/web/.next/server/chunks/ssr/{_baab52a9._.js.map → _c205e198._.js.map} +1 -1
  122. package/web/.next/server/chunks/ssr/_cc77a143._.js +1 -1
  123. package/web/.next/server/chunks/ssr/_cc77a143._.js.map +1 -1
  124. package/web/.next/server/chunks/ssr/b1a17_presentation_web_components_features_settings_settings-page-client_tsx_6ed9d5f8._.js +1 -1
  125. package/web/.next/server/chunks/ssr/b1a17_presentation_web_components_features_settings_settings-page-client_tsx_6ed9d5f8._.js.map +1 -1
  126. package/web/.next/server/chunks/ssr/src_presentation_web_7275ce5d._.js +2 -2
  127. package/web/.next/server/chunks/ssr/src_presentation_web_7275ce5d._.js.map +1 -1
  128. package/web/.next/server/chunks/ssr/src_presentation_web_758dfa10._.js +2 -2
  129. package/web/.next/server/chunks/ssr/src_presentation_web_758dfa10._.js.map +1 -1
  130. package/web/.next/server/chunks/ssr/src_presentation_web__next-internal_server_app_(dashboard)_page_actions_84803221.js +1 -1
  131. package/web/.next/server/chunks/ssr/src_presentation_web__next-internal_server_app_(dashboard)_page_actions_84803221.js.map +1 -1
  132. package/web/.next/server/chunks/ssr/src_presentation_web__next-internal_server_app_skills_page_actions_1fa8042e.js +1 -1
  133. package/web/.next/server/chunks/ssr/src_presentation_web__next-internal_server_app_skills_page_actions_1fa8042e.js.map +1 -1
  134. package/web/.next/server/chunks/ssr/src_presentation_web__next-internal_server_app_tools_page_actions_24684200.js +1 -1
  135. package/web/.next/server/chunks/ssr/src_presentation_web__next-internal_server_app_tools_page_actions_24684200.js.map +1 -1
  136. package/web/.next/server/chunks/ssr/src_presentation_web_components_bf50c527._.js +1 -1
  137. package/web/.next/server/chunks/ssr/src_presentation_web_components_de814675._.js +1 -1
  138. package/web/.next/server/chunks/ssr/src_presentation_web_components_features_control-center_7ac3562e._.js +1 -1
  139. package/web/.next/server/chunks/ssr/src_presentation_web_components_features_control-center_7ac3562e._.js.map +1 -1
  140. package/web/.next/server/pages/500.html +2 -2
  141. package/web/.next/server/server-reference-manifest.js +1 -1
  142. package/web/.next/server/server-reference-manifest.json +30 -30
  143. package/web/.next/static/chunks/{3b5a1f399be3c204.js → 09fe794bed5a0077.js} +1 -1
  144. package/web/.next/static/chunks/{5b52afbeb6af43f8.js → 20f5682099fbb10c.js} +1 -1
  145. package/web/.next/static/chunks/{2f3dedf11842dbb9.js → 2a63561f9716d615.js} +1 -1
  146. package/web/.next/static/chunks/3bba99704fc1d30c.js +1 -0
  147. package/web/.next/static/chunks/3fa3006034a0add8.css +1 -0
  148. package/web/.next/static/chunks/{c72a9bffb0609ccb.js → 47387a05a4f0f22b.js} +1 -1
  149. package/web/.next/static/chunks/4873b5f96cfdffb9.js +1 -0
  150. package/web/.next/static/chunks/{6f16220ca6a15488.js → 8c4731c87b599597.js} +1 -1
  151. package/web/.next/static/chunks/994e46e475fb78f9.js +2 -0
  152. package/web/.next/static/chunks/a8eceddc883b57bb.js +1 -0
  153. package/web/.next/static/chunks/b1f3c0e8e9872ef8.js +1 -0
  154. package/web/.next/static/chunks/{f164721e9111efd2.js → e7abc4f19da20094.js} +2 -2
  155. package/web/.next/server/chunks/ssr/[root-of-the-server]__d91fdd51._.js +0 -3
  156. package/web/.next/static/chunks/07b853e29af1e5f2.js +0 -1
  157. package/web/.next/static/chunks/2549eb5f74129ce6.js +0 -1
  158. package/web/.next/static/chunks/5a850475e2b3e8d7.js +0 -2
  159. package/web/.next/static/chunks/93058c22968e2fef.css +0 -1
  160. package/web/.next/static/chunks/d7acdf8831c942f1.js +0 -1
  161. package/web/.next/static/chunks/f8a27920b2acfead.js +0 -1
  162. /package/web/.next/static/{Bn9oiHUSrxNyoG9stevwc → vSr396p_Rdr92qmX9fzqd}/_buildManifest.js +0 -0
  163. /package/web/.next/static/{Bn9oiHUSrxNyoG9stevwc → vSr396p_Rdr92qmX9fzqd}/_clientMiddlewareManifest.json +0 -0
  164. /package/web/.next/static/{Bn9oiHUSrxNyoG9stevwc → vSr396p_Rdr92qmX9fzqd}/_ssgManifest.js +0 -0
@@ -1 +1 @@
1
- {"version":3,"file":"feature-drawer-client.d.ts","sourceRoot":"","sources":["../../../../../../../src/presentation/web/components/common/control-center-drawer/feature-drawer-client.tsx"],"names":[],"mappings":"AAsCA,OAAO,KAAK,EAAE,UAAU,EAAE,aAAa,EAAE,MAAM,eAAe,CAAC;AAG/D,MAAM,WAAW,wBAAwB;IACvC,IAAI,EAAE,UAAU,CAAC;IACjB,8FAA8F;IAC9F,MAAM,CAAC,EAAE,aAAa,CAAC;CACxB;AAED,wBAAgB,mBAAmB,CAAC,EAAE,IAAI,EAAE,WAAW,EAAE,MAAM,EAAE,EAAE,wBAAwB,2CA4iB1F"}
1
+ {"version":3,"file":"feature-drawer-client.d.ts","sourceRoot":"","sources":["../../../../../../../src/presentation/web/components/common/control-center-drawer/feature-drawer-client.tsx"],"names":[],"mappings":"AAsCA,OAAO,KAAK,EAAE,UAAU,EAAE,aAAa,EAAE,MAAM,eAAe,CAAC;AAG/D,MAAM,WAAW,wBAAwB;IACvC,IAAI,EAAE,UAAU,CAAC;IACjB,8FAA8F;IAC9F,MAAM,CAAC,EAAE,aAAa,CAAC;CACxB;AAED,wBAAgB,mBAAmB,CAAC,EAAE,IAAI,EAAE,WAAW,EAAE,MAAM,EAAE,EAAE,wBAAwB,2CA6iB1F"}
@@ -329,7 +329,7 @@ export function FeatureDrawerClient({ view: initialView, urlTab }) {
329
329
  // ── Body ──────────────────────────────────────────────────────────────
330
330
  let body = null;
331
331
  if (view.type === 'feature' && featureNode) {
332
- body = (_jsx(FeatureDrawerTabs, { featureNode: featureNode, featureId: featureNode.featureId, initialTab: view.initialTab, urlTab: urlTab, prdData: prdData, prdSelections: prdSelections, onPrdSelect: (qId, oId) => setPrdSelections((prev) => ({ ...prev, [qId]: oId })), onPrdApprove: handlePrdApprove, onPrdReject: handlePrdReject, isPrdLoading: isLoadingPrd, techData: techData, onTechApprove: handleTechApprove, onTechReject: handleTechReject, isTechLoading: isLoadingTech, productData: isLoadingTechProduct ? null : techProductData, mergeData: mergeData, onMergeApprove: handleMergeApprove, onMergeReject: handleMergeReject, isMergeLoading: isLoadingMerge, isRejecting: isRejecting, chatInput: chatInput, onChatInputChange: setChatInput }));
332
+ body = (_jsx(FeatureDrawerTabs, { featureNode: featureNode, featureId: featureNode.featureId, initialTab: view.initialTab, urlTab: urlTab, sseEvents: events, prdData: prdData, prdSelections: prdSelections, onPrdSelect: (qId, oId) => setPrdSelections((prev) => ({ ...prev, [qId]: oId })), onPrdApprove: handlePrdApprove, onPrdReject: handlePrdReject, isPrdLoading: isLoadingPrd, techData: techData, onTechApprove: handleTechApprove, onTechReject: handleTechReject, isTechLoading: isLoadingTech, productData: isLoadingTechProduct ? null : techProductData, mergeData: mergeData, onMergeApprove: handleMergeApprove, onMergeReject: handleMergeReject, isMergeLoading: isLoadingMerge, isRejecting: isRejecting, chatInput: chatInput, onChatInputChange: setChatInput }));
333
333
  }
334
334
  return (_jsx(BaseDrawer, { open: isOpen, onClose: attemptClose, size: "md", modal: false, header: header, "data-testid": view.type === 'feature' ? 'feature-drawer' : 'repository-drawer', children: body }));
335
335
  }
@@ -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":"AAGA,OAAO,KAAK,EACV,eAAe,EACf,qBAAqB,EACtB,MAAM,yCAAyC,CAAC;AAIjD,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,2CAyD3F"}
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;AA8CjD,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,2CA4D3F"}
@@ -1,8 +1,48 @@
1
1
  'use client';
2
2
  import { jsx as _jsx, jsxs as _jsxs, Fragment as _Fragment } from "react/jsx-runtime";
3
+ import { useState, useEffect, useRef } from 'react';
3
4
  import { Loader2, AlertCircle, Clock } from 'lucide-react';
4
5
  import { InlineAttachments } from '../../common/inline-attachments/index.js';
5
6
  import { formatDuration } from '../../../lib/format-duration.js';
7
+ /**
8
+ * Computes the effective duration for a phase timing entry.
9
+ * For completed phases, uses the server-provided durationMs.
10
+ * For in-progress phases (has startedAt but no completedAt), computes
11
+ * elapsed time client-side so the UI shows a live-updating timer.
12
+ */
13
+ function getEffectiveDuration(timing, now) {
14
+ if (timing.durationMs != null && timing.durationMs > 0)
15
+ return timing.durationMs;
16
+ if (!timing.completedAt && timing.startedAt) {
17
+ const started = new Date(timing.startedAt).getTime();
18
+ if (!Number.isNaN(started))
19
+ return Math.max(0, now - started);
20
+ }
21
+ return 0;
22
+ }
23
+ /** Returns true if any non-lifecycle phase is still in progress. */
24
+ function hasRunningPhase(timings) {
25
+ return timings.some((t) => !t.phase.startsWith('run:') && !t.completedAt && t.startedAt);
26
+ }
27
+ /** Hook that ticks every second while there are running phases. */
28
+ function useTickingNow(timings) {
29
+ const [now, setNow] = useState(Date.now);
30
+ const intervalRef = useRef(null);
31
+ useEffect(() => {
32
+ const running = timings ? hasRunningPhase(timings) : false;
33
+ if (running) {
34
+ // Tick every second
35
+ intervalRef.current = setInterval(() => setNow(Date.now()), 1000);
36
+ }
37
+ return () => {
38
+ if (intervalRef.current) {
39
+ clearInterval(intervalRef.current);
40
+ intervalRef.current = null;
41
+ }
42
+ };
43
+ }, [timings]);
44
+ return now;
45
+ }
6
46
  const NODE_TO_PHASE = {
7
47
  analyze: 'Analyzing',
8
48
  requirements: 'Requirements',
@@ -94,6 +134,7 @@ export function buildLifecycleTimeline(timings, feedback) {
94
134
  * Component
95
135
  * ------------------------------------------------------------------------- */
96
136
  export function ActivityTab({ timings, loading, error, rejectionFeedback }) {
137
+ const now = useTickingNow(timings);
97
138
  if (loading) {
98
139
  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" }) }));
99
140
  }
@@ -104,24 +145,24 @@ export function ActivityTab({ timings, loading, error, rejectionFeedback }) {
104
145
  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" })] }));
105
146
  }
106
147
  const nodeTimings = timings.filter((t) => !isLifecycleEvent(t.phase));
107
- const maxDurationMs = Math.max(...nodeTimings.map((t) => t.durationMs ?? 0), ...nodeTimings.map((t) => t.approvalWaitMs ?? 0), 0);
148
+ const maxDurationMs = Math.max(...nodeTimings.map((t) => getEffectiveDuration(t, now)), ...nodeTimings.map((t) => t.approvalWaitMs ?? 0), 0);
108
149
  const iterations = buildLifecycleTimeline(timings, rejectionFeedback);
109
150
  const hasMultipleIterations = iterations.length > 1;
110
- const totalExecMs = nodeTimings.reduce((sum, t) => sum + (t.durationMs ?? 0), 0);
151
+ const totalExecMs = nodeTimings.reduce((sum, t) => sum + getEffectiveDuration(t, now), 0);
111
152
  const totalWaitMs = nodeTimings.reduce((sum, t) => sum + (t.approvalWaitMs ?? 0), 0);
112
- 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 }, iteration.number))) }), totalExecMs > 0 ? (_jsx(SummaryTotals, { totalExecMs: totalExecMs, totalWaitMs: totalWaitMs })) : null] }));
153
+ 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 })) : null] }));
113
154
  }
114
155
  /* ---------------------------------------------------------------------------
115
156
  * Iteration group — one cycle of work
116
157
  * ------------------------------------------------------------------------- */
117
- function IterationGroup({ iteration, showHeader, maxDurationMs, }) {
158
+ function IterationGroup({ iteration, showHeader, maxDurationMs, now, }) {
118
159
  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) => {
119
160
  if (isLifecycleEvent(t.phase)) {
120
161
  // For run:rejected, the message comes from the iteration, not a separate map
121
162
  const isRejection = t.phase === 'run:rejected';
122
163
  return (_jsx(LifecycleEventRow, { timing: t, message: isRejection ? iteration.rejectionMessage : undefined, attachments: isRejection ? iteration.rejectionAttachments : undefined }, `${t.agentRunId}-${t.phase}-${t.startedAt}`));
123
164
  }
124
- return (_jsx(NodeTimingRow, { timing: t, maxDurationMs: maxDurationMs }, `${t.agentRunId}-${t.phase}-${t.startedAt}`));
165
+ return (_jsx(NodeTimingRow, { timing: t, maxDurationMs: maxDurationMs, now: now }, `${t.agentRunId}-${t.phase}-${t.startedAt}`));
125
166
  })] }));
126
167
  }
127
168
  /* ---------------------------------------------------------------------------
@@ -134,14 +175,15 @@ function LifecycleEventRow({ timing, message, attachments, }) {
134
175
  const hasAttachments = attachments && attachments.length > 0;
135
176
  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] }));
136
177
  }
137
- function NodeTimingRow({ timing, maxDurationMs, }) {
178
+ function NodeTimingRow({ timing, maxDurationMs, now, }) {
138
179
  const label = timing.phase.includes(':')
139
180
  ? `rev ${timing.phase.split(':')[1]}`
140
181
  : (NODE_TO_PHASE[timing.phase] ?? timing.phase);
141
- const durationMs = timing.durationMs ?? 0;
182
+ const durationMs = getEffectiveDuration(timing, now);
142
183
  const barPercent = maxDurationMs > 0 ? Math.max(2, (durationMs / maxDurationMs) * 100) : 2;
184
+ const isRunning = !timing.completedAt && !!timing.startedAt;
143
185
  const barColorClass = timing.completedAt ? 'bg-emerald-500' : 'bg-blue-500';
144
- return (_jsxs("div", { className: "flex flex-col gap-1", children: [_jsxs("div", { "data-testid": `timing-bar-${timing.phase}`, className: "flex items-center gap-3", children: [_jsx("span", { className: "text-muted-foreground w-24 shrink-0 text-xs", children: label }), _jsx("div", { className: "bg-muted h-3 flex-1 overflow-hidden rounded-full", children: _jsx("div", { className: `h-full rounded-full ${barColorClass}`, style: { width: `${Math.min(barPercent, 100)}%` } }) }), _jsx("span", { className: "text-muted-foreground w-14 shrink-0 text-right text-xs", children: formatDuration(durationMs) })] }), timing.approvalWaitMs != null && timing.approvalWaitMs > 0 ? (_jsx(ApprovalWaitRow, { timing: timing, maxDurationMs: maxDurationMs })) : null] }));
186
+ return (_jsxs("div", { className: "flex flex-col gap-1", children: [_jsxs("div", { "data-testid": `timing-bar-${timing.phase}`, className: "flex items-center gap-3", children: [_jsx("span", { className: "text-muted-foreground w-24 shrink-0 text-xs", children: label }), _jsx("div", { className: "bg-muted h-3 flex-1 overflow-hidden rounded-full", 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-14 shrink-0 text-right text-xs", children: formatDuration(durationMs) })] }), timing.approvalWaitMs != null && timing.approvalWaitMs > 0 ? (_jsx(ApprovalWaitRow, { timing: timing, maxDurationMs: maxDurationMs })) : null] }));
145
187
  }
146
188
  function ApprovalWaitRow({ timing, maxDurationMs, }) {
147
189
  const waitMs = timing.approvalWaitMs ?? 0;
@@ -0,0 +1,5 @@
1
+ export interface EventLogViewerProps {
2
+ content: string;
3
+ }
4
+ export declare function EventLogViewer({ content }: EventLogViewerProps): import("react/jsx-runtime").JSX.Element | null;
5
+ //# sourceMappingURL=event-log-viewer.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"event-log-viewer.d.ts","sourceRoot":"","sources":["../../../../../../../src/presentation/web/components/common/feature-drawer-tabs/event-log-viewer.tsx"],"names":[],"mappings":"AAwBA,MAAM,WAAW,mBAAmB;IAClC,OAAO,EAAE,MAAM,CAAC;CACjB;AAED,wBAAgB,cAAc,CAAC,EAAE,OAAO,EAAE,EAAE,mBAAmB,kDAY9D"}
@@ -0,0 +1,113 @@
1
+ 'use client';
2
+ import { jsx as _jsx, jsxs as _jsxs } from "react/jsx-runtime";
3
+ import { useMemo } from 'react';
4
+ import { FileText, Terminal, MessageSquare, CheckCircle2, Coins, Server, FileCode, } from 'lucide-react';
5
+ import { parseLogContent, parseToolCall, parseResultMessage, parseTokensMessage, } from '../../../lib/parse-log-line.js';
6
+ export function EventLogViewer({ content }) {
7
+ const lines = useMemo(() => parseLogContent(content), [content]);
8
+ if (lines.length === 0)
9
+ return null;
10
+ return (_jsx("div", { className: "flex flex-col", children: lines.map((line) => (_jsx(LogLineRow, { line: line }, line.raw))) }));
11
+ }
12
+ /* ---------------------------------------------------------------------------
13
+ * Line router
14
+ * ------------------------------------------------------------------------- */
15
+ function LogLineRow({ line }) {
16
+ switch (line.tag) {
17
+ case 'tool':
18
+ return _jsx(ToolCallRow, { line: line });
19
+ case 'text':
20
+ return _jsx(TextRow, { line: line });
21
+ case 'result':
22
+ return _jsx(ResultRow, { line: line });
23
+ case 'tokens':
24
+ return _jsx(TokensRow, { line: line });
25
+ case 'worker':
26
+ return _jsx(WorkerRow, { line: line });
27
+ case 'info':
28
+ return _jsx(InfoRow, { line: line });
29
+ case 'raw':
30
+ default:
31
+ return _jsx(RawRow, { line: line });
32
+ }
33
+ }
34
+ /* ---------------------------------------------------------------------------
35
+ * Shared helpers
36
+ * ------------------------------------------------------------------------- */
37
+ function Timestamp({ value }) {
38
+ if (!value)
39
+ return null;
40
+ const time = value.replace(/^.*T/, '').replace('Z', '');
41
+ return (_jsx("span", { className: "text-muted-foreground/60 w-20 shrink-0 font-mono text-[10px]", children: time }));
42
+ }
43
+ function PhaseBadge({ phase }) {
44
+ if (!phase)
45
+ return null;
46
+ return (_jsx("span", { className: "bg-muted text-muted-foreground shrink-0 rounded px-1.5 py-0.5 font-mono text-[10px] font-medium", children: phase }));
47
+ }
48
+ /* ---------------------------------------------------------------------------
49
+ * Event-specific rows
50
+ * ------------------------------------------------------------------------- */
51
+ function ToolCallRow({ line }) {
52
+ const { toolName, args } = parseToolCall(line.message);
53
+ // Try to extract a key detail from args for common tools
54
+ const detail = getToolDetail(toolName, args);
55
+ return (_jsxs("div", { className: "hover:bg-muted/50 flex items-start gap-2 border-b border-transparent px-3 py-1.5 transition-colors", children: [_jsx(Timestamp, { value: line.timestamp }), _jsx(PhaseBadge, { phase: line.phase }), _jsxs("div", { className: "flex min-w-0 flex-1 items-start gap-1.5", children: [_jsx(ToolIcon, { toolName: toolName }), _jsx("span", { className: "text-xs font-semibold text-violet-600 dark:text-violet-400", children: toolName }), detail ? (_jsx("span", { className: "text-muted-foreground min-w-0 truncate font-mono text-xs", children: detail })) : null] })] }));
56
+ }
57
+ function ToolIcon({ toolName }) {
58
+ const lower = toolName.toLowerCase();
59
+ if (lower === 'bash')
60
+ return _jsx(Terminal, { className: "mt-0.5 h-3 w-3 shrink-0 text-violet-500" });
61
+ if (lower === 'read' || lower === 'glob' || lower === 'grep')
62
+ return _jsx(FileText, { className: "mt-0.5 h-3 w-3 shrink-0 text-violet-500" });
63
+ if (lower === 'write' || lower === 'edit')
64
+ return _jsx(FileCode, { className: "mt-0.5 h-3 w-3 shrink-0 text-violet-500" });
65
+ return _jsx(Terminal, { className: "mt-0.5 h-3 w-3 shrink-0 text-violet-500" });
66
+ }
67
+ function getToolDetail(toolName, args) {
68
+ try {
69
+ const parsed = JSON.parse(args);
70
+ if (toolName === 'Read' && parsed.file_path)
71
+ return parsed.file_path;
72
+ if (toolName === 'Write' && parsed.file_path)
73
+ return parsed.file_path;
74
+ if (toolName === 'Edit' && parsed.file_path)
75
+ return parsed.file_path;
76
+ if (toolName === 'Glob' && parsed.pattern)
77
+ return parsed.pattern;
78
+ if (toolName === 'Grep' && parsed.pattern)
79
+ return parsed.pattern;
80
+ if (toolName === 'Bash' && parsed.command) {
81
+ const cmd = parsed.command;
82
+ return cmd.length > 80 ? `${cmd.slice(0, 80)}...` : cmd;
83
+ }
84
+ if (toolName === 'Task' && parsed.description)
85
+ return parsed.description;
86
+ }
87
+ catch {
88
+ // Not JSON — show truncated raw args
89
+ if (args.length > 0)
90
+ return args.length > 80 ? `${args.slice(0, 80)}...` : args;
91
+ }
92
+ return null;
93
+ }
94
+ function TextRow({ line }) {
95
+ return (_jsxs("div", { className: "hover:bg-muted/50 flex items-start gap-2 px-3 py-1.5 transition-colors", children: [_jsx(Timestamp, { value: line.timestamp }), _jsx(PhaseBadge, { phase: line.phase }), _jsxs("div", { className: "flex min-w-0 flex-1 items-start gap-1.5", children: [_jsx(MessageSquare, { className: "mt-0.5 h-3 w-3 shrink-0 text-blue-500" }), _jsx("span", { className: "text-foreground/80 min-w-0 text-xs leading-relaxed", children: line.message })] })] }));
96
+ }
97
+ function ResultRow({ line }) {
98
+ const { chars } = parseResultMessage(line.message);
99
+ return (_jsxs("div", { className: "hover:bg-muted/50 flex items-start gap-2 px-3 py-1.5 transition-colors", children: [_jsx(Timestamp, { value: line.timestamp }), _jsx(PhaseBadge, { phase: line.phase }), _jsxs("div", { className: "flex min-w-0 flex-1 items-start gap-1.5", children: [_jsx(CheckCircle2, { className: "mt-0.5 h-3 w-3 shrink-0 text-emerald-500" }), _jsxs("span", { className: "text-xs font-medium text-emerald-600 dark:text-emerald-400", children: ["Result: ", chars.toLocaleString(), " chars"] })] })] }));
100
+ }
101
+ function TokensRow({ line }) {
102
+ const { inputTokens, outputTokens } = parseTokensMessage(line.message);
103
+ return (_jsxs("div", { className: "hover:bg-muted/50 flex items-start gap-2 px-3 py-1.5 transition-colors", children: [_jsx(Timestamp, { value: line.timestamp }), _jsx(PhaseBadge, { phase: line.phase }), _jsxs("div", { className: "flex min-w-0 flex-1 items-start gap-1.5", children: [_jsx(Coins, { className: "mt-0.5 h-3 w-3 shrink-0 text-amber-500" }), _jsxs("span", { className: "text-muted-foreground text-xs", children: [_jsx("span", { className: "text-amber-600 dark:text-amber-400", children: inputTokens.toLocaleString() }), ' in / ', _jsx("span", { className: "text-amber-600 dark:text-amber-400", children: outputTokens.toLocaleString() }), ' out'] })] })] }));
104
+ }
105
+ function WorkerRow({ line }) {
106
+ return (_jsxs("div", { className: "hover:bg-muted/50 flex items-start gap-2 bg-zinc-50 px-3 py-1.5 transition-colors dark:bg-zinc-900/50", children: [_jsx(Timestamp, { value: line.timestamp }), _jsxs("div", { className: "flex min-w-0 flex-1 items-start gap-1.5", children: [_jsx(Server, { className: "mt-0.5 h-3 w-3 shrink-0 text-zinc-500" }), _jsx("span", { className: "text-muted-foreground text-xs font-medium", children: line.message })] })] }));
107
+ }
108
+ function InfoRow({ line }) {
109
+ return (_jsxs("div", { className: "hover:bg-muted/50 flex items-start gap-2 px-3 py-1.5 transition-colors", children: [_jsx(Timestamp, { value: line.timestamp }), _jsx(PhaseBadge, { phase: line.phase }), _jsx("span", { className: "text-muted-foreground min-w-0 text-xs", children: line.message })] }));
110
+ }
111
+ function RawRow({ line }) {
112
+ return (_jsx("div", { className: "px-3 py-0.5", children: _jsx("span", { className: "text-muted-foreground/70 font-mono text-[11px] break-all whitespace-pre-wrap", children: line.raw }) }));
113
+ }
@@ -0,0 +1,18 @@
1
+ import type { Meta, StoryObj } from '@storybook/react';
2
+ import { EventLogViewer } from './event-log-viewer.js';
3
+ declare const meta: Meta<typeof EventLogViewer>;
4
+ export default meta;
5
+ type Story = StoryObj<typeof EventLogViewer>;
6
+ /** ToolCalls — various tool call types */
7
+ export declare const ToolCalls: Story;
8
+ /** TextMessages — agent thinking/analysis */
9
+ export declare const TextMessages: Story;
10
+ /** WorkerLifecycle — worker bootstrap and shutdown */
11
+ export declare const WorkerLifecycle: Story;
12
+ /** ResultsAndTokens — completion summaries */
13
+ export declare const ResultsAndTokens: Story;
14
+ /** MixedContent — all event types including raw fallback */
15
+ export declare const MixedContent: Story;
16
+ /** EmptyContent — no content */
17
+ export declare const EmptyContent: Story;
18
+ //# sourceMappingURL=event-log-viewer.stories.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"event-log-viewer.stories.d.ts","sourceRoot":"","sources":["../../../../../../../src/presentation/web/components/common/feature-drawer-tabs/event-log-viewer.stories.tsx"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,IAAI,EAAE,QAAQ,EAAE,MAAM,kBAAkB,CAAC;AACvD,OAAO,EAAE,cAAc,EAAE,MAAM,oBAAoB,CAAC;AAEpD,QAAA,MAAM,IAAI,EAAE,IAAI,CAAC,OAAO,cAAc,CAqBrC,CAAC;AAEF,eAAe,IAAI,CAAC;AACpB,KAAK,KAAK,GAAG,QAAQ,CAAC,OAAO,cAAc,CAAC,CAAC;AAsD7C,0CAA0C;AAC1C,eAAO,MAAM,SAAS,EAAE,KAEvB,CAAC;AAEF,6CAA6C;AAC7C,eAAO,MAAM,YAAY,EAAE,KAE1B,CAAC;AAEF,sDAAsD;AACtD,eAAO,MAAM,eAAe,EAAE,KAE7B,CAAC;AAEF,8CAA8C;AAC9C,eAAO,MAAM,gBAAgB,EAAE,KAE9B,CAAC;AAEF,4DAA4D;AAC5D,eAAO,MAAM,YAAY,EAAE,KAE1B,CAAC;AAEF,gCAAgC;AAChC,eAAO,MAAM,YAAY,EAAE,KAE1B,CAAC"}
@@ -0,0 +1,88 @@
1
+ import { jsx as _jsx } from "react/jsx-runtime";
2
+ import { EventLogViewer } from './event-log-viewer.js';
3
+ const meta = {
4
+ title: 'Drawers/Feature/Tabs/EventLogViewer',
5
+ component: EventLogViewer,
6
+ tags: ['autodocs'],
7
+ parameters: {
8
+ layout: 'fullscreen',
9
+ },
10
+ decorators: [
11
+ (Story) => (_jsx("div", { style: {
12
+ height: '600px',
13
+ width: '480px',
14
+ border: '1px solid var(--color-border)',
15
+ overflow: 'auto',
16
+ }, children: _jsx(Story, {}) })),
17
+ ],
18
+ };
19
+ export default meta;
20
+ /* ---------------------------------------------------------------------------
21
+ * Fixtures
22
+ * ------------------------------------------------------------------------- */
23
+ const toolEvents = `[2026-03-08T10:00:08.234Z] [requirements] [claude-code|claude-sonnet-4-6] [tool] Read {"file_path": "src/main.ts"}
24
+ [2026-03-08T10:00:10.345Z] [requirements] [claude-code|claude-sonnet-4-6] [tool] Glob {"pattern": "src/**/*.ts"}
25
+ [2026-03-08T10:00:12.567Z] [requirements] [claude-code|claude-sonnet-4-6] [tool] Grep {"pattern": "interface.*Auth", "path": "src/"}
26
+ [2026-03-08T10:00:14.789Z] [requirements] [claude-code|claude-sonnet-4-6] [tool] Bash {"command": "find src -name '*.test.ts' | wc -l"}
27
+ [2026-03-08T10:00:16.012Z] [implement] [claude-code|claude-sonnet-4-6] [tool] Write {"file_path": "src/auth/oauth-provider.ts"}
28
+ [2026-03-08T10:00:18.234Z] [implement] [claude-code|claude-sonnet-4-6] [tool] Edit {"file_path": "src/auth/index.ts"}
29
+ [2026-03-08T10:00:20.456Z] [implement] [claude-code|claude-sonnet-4-6] [tool] Task {"description": "Run integration tests"}`;
30
+ const textEvents = `[2026-03-08T10:00:10.345Z] [requirements] [claude-code|claude-sonnet-4-6] [text] Analyzing the codebase structure and identifying key entry points for the authentication module
31
+ [2026-03-08T10:00:18.234Z] [requirements] [claude-code|claude-sonnet-4-6] [text] The project uses a clean architecture pattern with dependency injection
32
+ [2026-03-08T10:02:38.200Z] [plan] [claude-code|claude-sonnet-4-6] [text] Creating implementation plan with TDD approach as required by project conventions
33
+ [2026-03-08T10:05:30.000Z] [implement] [claude-code|claude-sonnet-4-6] [text] All 14 unit tests passing. Moving to integration tests`;
34
+ const workerEvents = `[2026-03-08T10:00:01.000Z] [claude-code|claude-sonnet-4-6] [WORKER] Starting worker — full command:
35
+ [2026-03-08T10:00:01.001Z] [claude-code|claude-sonnet-4-6] [WORKER] feature-agent-worker --feature-id auth-module --run-id run-123
36
+ [2026-03-08T10:00:01.010Z] [claude-code|claude-sonnet-4-6] [WORKER] Initializing container...
37
+ [2026-03-08T10:00:01.050Z] [claude-code|claude-sonnet-4-6] [WORKER] Creating executor from pinned agent type: claude-code
38
+ [2026-03-08T10:00:01.100Z] [claude-code|claude-sonnet-4-6] [WORKER] Updating status to running (PID 54321)...
39
+ [2026-03-08T10:06:00.000Z] [claude-code|claude-sonnet-4-6] [WORKER] Graph invocation completed. Error: none
40
+ [2026-03-08T10:06:00.100Z] [claude-code|claude-sonnet-4-6] [WORKER] Run marked as completed
41
+ [2026-03-08T10:06:00.200Z] [claude-code|claude-sonnet-4-6] [WORKER] Worker completed successfully, exiting.`;
42
+ const resultAndTokenEvents = `[2026-03-08T10:00:45.789Z] [requirements] [claude-code|claude-sonnet-4-6] [result] 8920 chars, session=sess-abc123def456
43
+ [2026-03-08T10:00:45.790Z] [requirements] [claude-code|claude-sonnet-4-6] [tokens] 2450 in / 4560 out
44
+ [2026-03-08T10:03:15.234Z] [plan] [claude-code|claude-sonnet-4-6] [result] 12345 chars, session=sess-abc123def456
45
+ [2026-03-08T10:03:15.235Z] [plan] [claude-code|claude-sonnet-4-6] [tokens] 8900 in / 3456 out
46
+ [2026-03-08T10:05:55.000Z] [implement] [claude-code|claude-sonnet-4-6] [result] 24560 chars, session=sess-abc123def456
47
+ [2026-03-08T10:05:55.001Z] [implement] [claude-code|claude-sonnet-4-6] [tokens] 15200 in / 9360 out`;
48
+ const mixedContent = `[2026-03-08T10:00:01.000Z] [claude-code|claude-sonnet-4-6] [WORKER] Starting worker — full command:
49
+ [2026-03-08T10:00:01.010Z] [claude-code|claude-sonnet-4-6] [WORKER] Initializing container...
50
+ [2026-03-08T10:00:05.000Z] [requirements] [claude-code|claude-sonnet-4-6] Starting...
51
+ [2026-03-08T10:00:08.234Z] [requirements] [claude-code|claude-sonnet-4-6] [tool] Read {"file_path": "src/main.ts"}
52
+ [2026-03-08T10:00:10.345Z] [requirements] [claude-code|claude-sonnet-4-6] [text] Analyzing the codebase structure
53
+ [2026-03-08T10:00:12.567Z] [requirements] [claude-code|claude-sonnet-4-6] [tool] Bash {"command": "pnpm test:unit"}
54
+ [2026-03-08T10:00:45.789Z] [requirements] [claude-code|claude-sonnet-4-6] [result] 8920 chars, session=sess-abc123
55
+ [2026-03-08T10:00:45.790Z] [requirements] [claude-code|claude-sonnet-4-6] [tokens] 2450 in / 4560 out
56
+ Some unstructured output that doesn't match the format
57
+ Another raw line from stderr
58
+ [2026-03-08T10:02:30.100Z] [plan] [claude-code|claude-sonnet-4-6] Starting...
59
+ [2026-03-08T10:02:35.100Z] [plan] [claude-code|claude-sonnet-4-6] [tool] Write {"file_path": "specs/001-auth/plan.yaml"}
60
+ [2026-03-08T10:03:15.234Z] [plan] [claude-code|claude-sonnet-4-6] [result] 12345 chars, session=sess-abc123
61
+ [2026-03-08T10:03:15.235Z] [plan] [claude-code|claude-sonnet-4-6] [tokens] 8900 in / 3456 out`;
62
+ /* ---------------------------------------------------------------------------
63
+ * Stories
64
+ * ------------------------------------------------------------------------- */
65
+ /** ToolCalls — various tool call types */
66
+ export const ToolCalls = {
67
+ args: { content: toolEvents },
68
+ };
69
+ /** TextMessages — agent thinking/analysis */
70
+ export const TextMessages = {
71
+ args: { content: textEvents },
72
+ };
73
+ /** WorkerLifecycle — worker bootstrap and shutdown */
74
+ export const WorkerLifecycle = {
75
+ args: { content: workerEvents },
76
+ };
77
+ /** ResultsAndTokens — completion summaries */
78
+ export const ResultsAndTokens = {
79
+ args: { content: resultAndTokenEvents },
80
+ };
81
+ /** MixedContent — all event types including raw fallback */
82
+ export const MixedContent = {
83
+ args: { content: mixedContent },
84
+ };
85
+ /** EmptyContent — no content */
86
+ export const EmptyContent = {
87
+ args: { content: '' },
88
+ };
@@ -1,3 +1,4 @@
1
+ import type { NotificationEvent } from '../../../../../../packages/core/src/domain/generated/output.js';
1
2
  import type { FeatureNodeData } from '../../common/feature-node/index.js';
2
3
  import type { PrdQuestionnaireData } from '../../common/prd-questionnaire/index.js';
3
4
  import type { TechDecisionsReviewData } from '../../common/tech-decisions-review/index.js';
@@ -11,6 +12,8 @@ export interface FeatureDrawerTabsProps {
11
12
  initialTab?: FeatureTabKey;
12
13
  /** Tab key from URL path segment (e.g. /feature/[id]/activity → 'activity'). */
13
14
  urlTab?: FeatureTabKey;
15
+ /** SSE events from the agent events provider, used to trigger tab data refresh. */
16
+ sseEvents?: readonly NotificationEvent[];
14
17
  prdData?: PrdQuestionnaireData | null;
15
18
  prdSelections?: Record<string, string>;
16
19
  onPrdSelect?: (questionId: string, optionId: string) => void;
@@ -30,5 +33,5 @@ export interface FeatureDrawerTabsProps {
30
33
  chatInput?: string;
31
34
  onChatInputChange?: (value: string) => void;
32
35
  }
33
- export declare function FeatureDrawerTabs({ featureNode, featureId, initialTab, urlTab, prdData, prdSelections, onPrdSelect, onPrdApprove, onPrdReject, isPrdLoading, techData, onTechApprove, onTechReject, isTechLoading, productData, mergeData, onMergeApprove, onMergeReject, isMergeLoading, isRejecting, chatInput, onChatInputChange, }: FeatureDrawerTabsProps): import("react/jsx-runtime").JSX.Element;
36
+ export declare function FeatureDrawerTabs({ featureNode, featureId, initialTab, urlTab, prdData, prdSelections, onPrdSelect, onPrdApprove, onPrdReject, isPrdLoading, techData, onTechApprove, onTechReject, isTechLoading, productData, mergeData, onMergeApprove, onMergeReject, isMergeLoading, isRejecting, chatInput, onChatInputChange, sseEvents, }: FeatureDrawerTabsProps): import("react/jsx-runtime").JSX.Element;
34
37
  //# sourceMappingURL=feature-drawer-tabs.d.ts.map
@@ -1 +1 @@
1
- {"version":3,"file":"feature-drawer-tabs.d.ts","sourceRoot":"","sources":["../../../../../../../src/presentation/web/components/common/feature-drawer-tabs/feature-drawer-tabs.tsx"],"names":[],"mappings":"AAaA,OAAO,KAAK,EAAE,eAAe,EAAE,MAAM,kCAAkC,CAAC;AACxE,OAAO,KAAK,EAAE,oBAAoB,EAAE,MAAM,uCAAuC,CAAC;AAClF,OAAO,KAAK,EAAE,uBAAuB,EAAE,MAAM,2CAA2C,CAAC;AACzF,OAAO,KAAK,EAAE,2BAA2B,EAAE,MAAM,+CAA+C,CAAC;AACjG,OAAO,KAAK,EAAE,eAAe,EAAE,MAAM,kCAAkC,CAAC;AAMxE,OAAO,KAAK,EAAE,gBAAgB,EAAE,MAAM,uCAAuC,CAAC;AAQ9E,OAAO,KAAK,EAAE,aAAa,EAAE,MAAM,uDAAuD,CAAC;AAiD3F,MAAM,WAAW,sBAAsB;IACrC,WAAW,EAAE,eAAe,CAAC;IAC7B,SAAS,EAAE,MAAM,CAAC;IAClB,UAAU,CAAC,EAAE,aAAa,CAAC;IAC3B,gFAAgF;IAChF,MAAM,CAAC,EAAE,aAAa,CAAC;IAGvB,OAAO,CAAC,EAAE,oBAAoB,GAAG,IAAI,CAAC;IACtC,aAAa,CAAC,EAAE,MAAM,CAAC,MAAM,EAAE,MAAM,CAAC,CAAC;IACvC,WAAW,CAAC,EAAE,CAAC,UAAU,EAAE,MAAM,EAAE,QAAQ,EAAE,MAAM,KAAK,IAAI,CAAC;IAC7D,YAAY,CAAC,EAAE,CAAC,QAAQ,EAAE,MAAM,KAAK,IAAI,CAAC;IAC1C,WAAW,CAAC,EAAE,CAAC,QAAQ,EAAE,MAAM,EAAE,WAAW,EAAE,gBAAgB,EAAE,KAAK,IAAI,CAAC;IAC1E,YAAY,CAAC,EAAE,OAAO,CAAC;IAGvB,QAAQ,CAAC,EAAE,uBAAuB,GAAG,IAAI,CAAC;IAC1C,aAAa,CAAC,EAAE,MAAM,IAAI,CAAC;IAC3B,YAAY,CAAC,EAAE,CAAC,QAAQ,EAAE,MAAM,EAAE,WAAW,EAAE,gBAAgB,EAAE,KAAK,IAAI,CAAC;IAC3E,aAAa,CAAC,EAAE,OAAO,CAAC;IAGxB,WAAW,CAAC,EAAE,2BAA2B,GAAG,IAAI,CAAC;IAGjD,SAAS,CAAC,EAAE,eAAe,GAAG,IAAI,CAAC;IACnC,cAAc,CAAC,EAAE,MAAM,IAAI,CAAC;IAC5B,aAAa,CAAC,EAAE,CAAC,QAAQ,EAAE,MAAM,EAAE,WAAW,EAAE,gBAAgB,EAAE,KAAK,IAAI,CAAC;IAC5E,cAAc,CAAC,EAAE,OAAO,CAAC;IAGzB,WAAW,CAAC,EAAE,OAAO,CAAC;IACtB,SAAS,CAAC,EAAE,MAAM,CAAC;IACnB,iBAAiB,CAAC,EAAE,CAAC,KAAK,EAAE,MAAM,KAAK,IAAI,CAAC;CAC7C;AAwBD,wBAAgB,iBAAiB,CAAC,EAChC,WAAW,EACX,SAAS,EACT,UAAU,EACV,MAAM,EACN,OAAO,EACP,aAAa,EACb,WAAW,EACX,YAAY,EACZ,WAAW,EACX,YAAY,EACZ,QAAQ,EACR,aAAa,EACb,YAAY,EACZ,aAAa,EACb,WAAW,EACX,SAAS,EACT,cAAc,EACd,aAAa,EACb,cAAc,EACd,WAAW,EACX,SAAS,EACT,iBAAiB,GAClB,EAAE,sBAAsB,2CAmSxB"}
1
+ {"version":3,"file":"feature-drawer-tabs.d.ts","sourceRoot":"","sources":["../../../../../../../src/presentation/web/components/common/feature-drawer-tabs/feature-drawer-tabs.tsx"],"names":[],"mappings":"AAKA,OAAO,KAAK,EAAE,iBAAiB,EAAE,MAAM,sCAAsC,CAAC;AAS9E,OAAO,KAAK,EAAE,eAAe,EAAE,MAAM,kCAAkC,CAAC;AACxE,OAAO,KAAK,EAAE,oBAAoB,EAAE,MAAM,uCAAuC,CAAC;AAClF,OAAO,KAAK,EAAE,uBAAuB,EAAE,MAAM,2CAA2C,CAAC;AACzF,OAAO,KAAK,EAAE,2BAA2B,EAAE,MAAM,+CAA+C,CAAC;AACjG,OAAO,KAAK,EAAE,eAAe,EAAE,MAAM,kCAAkC,CAAC;AAMxE,OAAO,KAAK,EAAE,gBAAgB,EAAE,MAAM,uCAAuC,CAAC;AAQ9E,OAAO,KAAK,EAAE,aAAa,EAAE,MAAM,uDAAuD,CAAC;AAiD3F,MAAM,WAAW,sBAAsB;IACrC,WAAW,EAAE,eAAe,CAAC;IAC7B,SAAS,EAAE,MAAM,CAAC;IAClB,UAAU,CAAC,EAAE,aAAa,CAAC;IAC3B,gFAAgF;IAChF,MAAM,CAAC,EAAE,aAAa,CAAC;IACvB,mFAAmF;IACnF,SAAS,CAAC,EAAE,SAAS,iBAAiB,EAAE,CAAC;IAGzC,OAAO,CAAC,EAAE,oBAAoB,GAAG,IAAI,CAAC;IACtC,aAAa,CAAC,EAAE,MAAM,CAAC,MAAM,EAAE,MAAM,CAAC,CAAC;IACvC,WAAW,CAAC,EAAE,CAAC,UAAU,EAAE,MAAM,EAAE,QAAQ,EAAE,MAAM,KAAK,IAAI,CAAC;IAC7D,YAAY,CAAC,EAAE,CAAC,QAAQ,EAAE,MAAM,KAAK,IAAI,CAAC;IAC1C,WAAW,CAAC,EAAE,CAAC,QAAQ,EAAE,MAAM,EAAE,WAAW,EAAE,gBAAgB,EAAE,KAAK,IAAI,CAAC;IAC1E,YAAY,CAAC,EAAE,OAAO,CAAC;IAGvB,QAAQ,CAAC,EAAE,uBAAuB,GAAG,IAAI,CAAC;IAC1C,aAAa,CAAC,EAAE,MAAM,IAAI,CAAC;IAC3B,YAAY,CAAC,EAAE,CAAC,QAAQ,EAAE,MAAM,EAAE,WAAW,EAAE,gBAAgB,EAAE,KAAK,IAAI,CAAC;IAC3E,aAAa,CAAC,EAAE,OAAO,CAAC;IAGxB,WAAW,CAAC,EAAE,2BAA2B,GAAG,IAAI,CAAC;IAGjD,SAAS,CAAC,EAAE,eAAe,GAAG,IAAI,CAAC;IACnC,cAAc,CAAC,EAAE,MAAM,IAAI,CAAC;IAC5B,aAAa,CAAC,EAAE,CAAC,QAAQ,EAAE,MAAM,EAAE,WAAW,EAAE,gBAAgB,EAAE,KAAK,IAAI,CAAC;IAC5E,cAAc,CAAC,EAAE,OAAO,CAAC;IAGzB,WAAW,CAAC,EAAE,OAAO,CAAC;IACtB,SAAS,CAAC,EAAE,MAAM,CAAC;IACnB,iBAAiB,CAAC,EAAE,CAAC,KAAK,EAAE,MAAM,KAAK,IAAI,CAAC;CAC7C;AAwBD,wBAAgB,iBAAiB,CAAC,EAChC,WAAW,EACX,SAAS,EACT,UAAU,EACV,MAAM,EACN,OAAO,EACP,aAAa,EACb,WAAW,EACX,YAAY,EACZ,WAAW,EACX,YAAY,EACZ,QAAQ,EACR,aAAa,EACb,YAAY,EACZ,aAAa,EACb,WAAW,EACX,SAAS,EACT,cAAc,EACd,aAAa,EACb,cAAc,EACd,WAAW,EACX,SAAS,EACT,iBAAiB,EACjB,SAAS,GACV,EAAE,sBAAsB,2CAwTxB"}
@@ -64,7 +64,7 @@ const TAB_FETCHERS = {
64
64
  activity: fetchActivity,
65
65
  plan: fetchPlan,
66
66
  };
67
- export function FeatureDrawerTabs({ featureNode, featureId, initialTab, urlTab, prdData, prdSelections, onPrdSelect, onPrdApprove, onPrdReject, isPrdLoading, techData, onTechApprove, onTechReject, isTechLoading, productData, mergeData, onMergeApprove, onMergeReject, isMergeLoading, isRejecting, chatInput, onChatInputChange, }) {
67
+ export function FeatureDrawerTabs({ featureNode, featureId, initialTab, urlTab, prdData, prdSelections, onPrdSelect, onPrdApprove, onPrdReject, isPrdLoading, techData, onTechApprove, onTechReject, isTechLoading, productData, mergeData, onMergeApprove, onMergeReject, isMergeLoading, isRejecting, chatInput, onChatInputChange, sseEvents, }) {
68
68
  const pathname = usePathname();
69
69
  const featureLogs = useFeatureLogs(featureId);
70
70
  const visibleTabs = useMemo(() => computeVisibleTabs(featureNode), [featureNode]);
@@ -159,6 +159,7 @@ export function FeatureDrawerTabs({ featureNode, featureId, initialTab, urlTab,
159
159
  }, [featureId]);
160
160
  // When initialTab changes (e.g. SSE updates lifecycle), switch to it if visible
161
161
  // and sync the URL with replaceState so the address bar reflects the new tab.
162
+ // Also trigger lazy fetch for the new tab so data is ready immediately.
162
163
  const prevInitialTabRef = useRef(initialTab);
163
164
  useEffect(() => {
164
165
  if (prevInitialTabRef.current !== initialTab &&
@@ -166,13 +167,17 @@ export function FeatureDrawerTabs({ featureNode, featureId, initialTab, urlTab,
166
167
  visibleTabs.includes(initialTab)) {
167
168
  prevInitialTabRef.current = initialTab;
168
169
  setActiveTab(initialTab);
170
+ // Trigger lazy fetch for the new tab if it's a lazy-loaded tab
171
+ if (initialTab === 'activity' || initialTab === 'plan') {
172
+ fetchTab(initialTab);
173
+ }
169
174
  // Sync URL to match the new tab
170
175
  const targetUrl = initialTab === 'overview' ? basePath : `${basePath}/${initialTab}`;
171
176
  if (targetUrl !== window.location.pathname) {
172
177
  window.history.replaceState(null, '', targetUrl);
173
178
  }
174
179
  }
175
- }, [initialTab, visibleTabs, basePath]);
180
+ }, [initialTab, visibleTabs, basePath, fetchTab]);
176
181
  // If the active tab becomes invisible (lifecycle changed), fall back to overview
177
182
  // and sync the URL accordingly.
178
183
  useEffect(() => {
@@ -183,19 +188,34 @@ export function FeatureDrawerTabs({ featureNode, featureId, initialTab, urlTab,
183
188
  }
184
189
  }
185
190
  }, [visibleTabs, activeTab, basePath]);
186
- // SSE refresh: re-fetch active lazy tab when featureNode reference changes
187
- const featureNodeRef = useRef(featureNode);
191
+ // SSE refresh: re-fetch lazy tab data when relevant SSE events arrive
192
+ // for this feature (e.g. PhaseCompleted, AgentStarted, AgentCompleted).
193
+ // Always refresh 'activity' data (even if not the active tab) so switching
194
+ // to the activity tab shows up-to-date timings without a loading flash.
188
195
  const activeTabRef = useRef(activeTab);
189
196
  activeTabRef.current = activeTab;
197
+ const sseProcessedRef = useRef(0);
190
198
  useEffect(() => {
191
- if (featureNodeRef.current !== featureNode) {
192
- featureNodeRef.current = featureNode;
193
- const current = activeTabRef.current;
194
- if (current === 'activity' || current === 'plan') {
195
- refreshTab(current);
196
- }
199
+ if (!sseEvents || sseEvents.length === 0)
200
+ return;
201
+ // Clamp cursor if events were pruned
202
+ if (sseProcessedRef.current > sseEvents.length) {
203
+ sseProcessedRef.current = 0;
204
+ }
205
+ if (sseEvents.length <= sseProcessedRef.current)
206
+ return;
207
+ const newEvents = sseEvents.slice(sseProcessedRef.current);
208
+ sseProcessedRef.current = sseEvents.length;
209
+ const hasRelevantEvent = newEvents.some((e) => e.featureId === featureId);
210
+ if (!hasRelevantEvent)
211
+ return;
212
+ // Always refresh activity data so it stays current for when the user switches tabs
213
+ refreshTab('activity');
214
+ const current = activeTabRef.current;
215
+ if (current === 'plan') {
216
+ refreshTab(current);
197
217
  }
198
- }, [featureNode, refreshTab]);
218
+ }, [sseEvents, featureId, refreshTab]);
199
219
  const handleTabChange = useCallback((value) => {
200
220
  const tab = value;
201
221
  isUserInteraction.current = true;
@@ -1 +1 @@
1
- {"version":3,"file":"log-tab.d.ts","sourceRoot":"","sources":["../../../../../../../src/presentation/web/components/common/feature-drawer-tabs/log-tab.tsx"],"names":[],"mappings":"AAKA,MAAM,WAAW,WAAW;IAC1B,OAAO,EAAE,MAAM,CAAC;IAChB,WAAW,EAAE,OAAO,CAAC;IACrB,KAAK,EAAE,MAAM,GAAG,IAAI,CAAC;CACtB;AAED,wBAAgB,MAAM,CAAC,EAAE,OAAO,EAAE,WAAW,EAAE,KAAK,EAAE,EAAE,WAAW,2CA6ElE"}
1
+ {"version":3,"file":"log-tab.d.ts","sourceRoot":"","sources":["../../../../../../../src/presentation/web/components/common/feature-drawer-tabs/log-tab.tsx"],"names":[],"mappings":"AAMA,MAAM,WAAW,WAAW;IAC1B,OAAO,EAAE,MAAM,CAAC;IAChB,WAAW,EAAE,OAAO,CAAC;IACrB,KAAK,EAAE,MAAM,GAAG,IAAI,CAAC;CACtB;AAID,wBAAgB,MAAM,CAAC,EAAE,OAAO,EAAE,WAAW,EAAE,KAAK,EAAE,EAAE,WAAW,2CAgHlE"}
@@ -1,10 +1,12 @@
1
1
  'use client';
2
2
  import { jsx as _jsx, jsxs as _jsxs } from "react/jsx-runtime";
3
3
  import { useRef, useEffect, useState, useCallback } from 'react';
4
- import { AlertCircle, Terminal, ArrowDown } from 'lucide-react';
4
+ import { AlertCircle, Terminal, ArrowDown, Code, FileText } from 'lucide-react';
5
+ import { EventLogViewer } from './event-log-viewer.js';
5
6
  export function LogTab({ content, isConnected, error }) {
6
7
  const containerRef = useRef(null);
7
8
  const [autoScroll, setAutoScroll] = useState(true);
9
+ const [viewMode, setViewMode] = useState('structured');
8
10
  const handleScroll = useCallback(() => {
9
11
  const el = containerRef.current;
10
12
  if (!el)
@@ -31,5 +33,11 @@ export function LogTab({ content, isConnected, error }) {
31
33
  if (!content) {
32
34
  return (_jsxs("div", { className: "flex flex-col items-center justify-center gap-2 p-8", children: [_jsx(Terminal, { className: "text-muted-foreground h-8 w-8" }), _jsx("p", { className: "text-muted-foreground text-sm", children: "No log output yet" }), isConnected ? (_jsx("p", { className: "text-muted-foreground text-xs", children: "Waiting for log data..." })) : null] }));
33
35
  }
34
- return (_jsxs("div", { className: "flex h-full flex-col", "data-testid": "log-tab", children: [_jsxs("div", { className: "flex items-center gap-2 border-b px-3 py-1.5", children: [_jsx("span", { className: `h-2 w-2 rounded-full ${isConnected ? 'bg-emerald-500' : 'bg-zinc-400'}` }), _jsx("span", { className: "text-muted-foreground text-xs", children: isConnected ? 'Live' : 'Disconnected' }), !autoScroll ? (_jsxs("button", { type: "button", onClick: jumpToBottom, className: "text-muted-foreground hover:text-foreground ml-auto flex items-center gap-1 text-xs", children: [_jsx(ArrowDown, { className: "h-3 w-3" }), "Jump to bottom"] })) : null] }), _jsx("div", { ref: containerRef, onScroll: handleScroll, className: "flex-1 overflow-y-auto bg-zinc-950 p-3 font-mono text-xs leading-relaxed break-all whitespace-pre-wrap text-zinc-300", children: content })] }));
36
+ return (_jsxs("div", { className: "flex h-full flex-col", "data-testid": "log-tab", children: [_jsxs("div", { className: "flex items-center gap-2 border-b px-3 py-1.5", children: [_jsx("span", { className: `h-2 w-2 rounded-full ${isConnected ? 'bg-emerald-500' : 'bg-zinc-400'}` }), _jsx("span", { className: "text-muted-foreground text-xs", children: isConnected ? 'Live' : 'Disconnected' }), _jsxs("div", { className: "ml-auto flex items-center gap-1", children: [_jsx("button", { type: "button", onClick: () => setViewMode('structured'), className: `rounded p-1 transition-colors ${viewMode === 'structured'
37
+ ? 'bg-muted text-foreground'
38
+ : 'text-muted-foreground hover:text-foreground'}`, title: "Structured view", children: _jsx(FileText, { className: "h-3.5 w-3.5" }) }), _jsx("button", { type: "button", onClick: () => setViewMode('raw'), className: `rounded p-1 transition-colors ${viewMode === 'raw'
39
+ ? 'bg-muted text-foreground'
40
+ : 'text-muted-foreground hover:text-foreground'}`, title: "Raw view", children: _jsx(Code, { className: "h-3.5 w-3.5" }) }), !autoScroll ? (_jsxs("button", { type: "button", onClick: jumpToBottom, className: "text-muted-foreground hover:text-foreground ml-1 flex items-center gap-1 text-xs", children: [_jsx(ArrowDown, { className: "h-3 w-3" }), "Jump to bottom"] })) : null] })] }), _jsx("div", { ref: containerRef, onScroll: handleScroll, className: `flex-1 overflow-y-auto ${viewMode === 'raw'
41
+ ? 'bg-zinc-950 p-3 font-mono text-xs leading-relaxed break-all whitespace-pre-wrap text-zinc-300'
42
+ : 'bg-background'}`, children: viewMode === 'structured' ? _jsx(EventLogViewer, { content: content }) : content })] }));
35
43
  }
@@ -3,10 +3,12 @@ import { LogTab } from './log-tab.js';
3
3
  declare const meta: Meta<typeof LogTab>;
4
4
  export default meta;
5
5
  type Story = StoryObj<typeof LogTab>;
6
- /** Default — typical agent log output with live connection. */
6
+ /** Default — structured agent log output with live connection (claude-code). */
7
7
  export declare const Default: Story;
8
- /** LongLog200 lines of log output to test scrolling behavior. */
9
- export declare const LongLog: Story;
8
+ /** LongStructured100 structured events to test scrolling behavior. */
9
+ export declare const LongStructured: Story;
10
+ /** RawFallback — unstructured log content falls back gracefully. */
11
+ export declare const RawFallback: Story;
10
12
  /** Disconnected — log content present but connection is lost. */
11
13
  export declare const Disconnected: Story;
12
14
  /** Empty — no log content yet, connected and waiting. */
@@ -1 +1 @@
1
- {"version":3,"file":"log-tab.stories.d.ts","sourceRoot":"","sources":["../../../../../../../src/presentation/web/components/common/feature-drawer-tabs/log-tab.stories.tsx"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,IAAI,EAAE,QAAQ,EAAE,MAAM,kBAAkB,CAAC;AACvD,OAAO,EAAE,MAAM,EAAE,MAAM,WAAW,CAAC;AAEnC,QAAA,MAAM,IAAI,EAAE,IAAI,CAAC,OAAO,MAAM,CAc7B,CAAC;AAEF,eAAe,IAAI,CAAC;AACpB,KAAK,KAAK,GAAG,QAAQ,CAAC,OAAO,MAAM,CAAC,CAAC;AAqCrC,+DAA+D;AAC/D,eAAO,MAAM,OAAO,EAAE,KAMrB,CAAC;AAEF,oEAAoE;AACpE,eAAO,MAAM,OAAO,EAAE,KAMrB,CAAC;AAEF,iEAAiE;AACjE,eAAO,MAAM,YAAY,EAAE,KAM1B,CAAC;AAEF,yDAAyD;AACzD,eAAO,MAAM,KAAK,EAAE,KAMnB,CAAC;AAEF,4DAA4D;AAC5D,eAAO,MAAM,iBAAiB,EAAE,KAM/B,CAAC;AAEF,6DAA6D;AAC7D,eAAO,MAAM,KAAK,EAAE,KAMnB,CAAC"}
1
+ {"version":3,"file":"log-tab.stories.d.ts","sourceRoot":"","sources":["../../../../../../../src/presentation/web/components/common/feature-drawer-tabs/log-tab.stories.tsx"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,IAAI,EAAE,QAAQ,EAAE,MAAM,kBAAkB,CAAC;AACvD,OAAO,EAAE,MAAM,EAAE,MAAM,WAAW,CAAC;AAEnC,QAAA,MAAM,IAAI,EAAE,IAAI,CAAC,OAAO,MAAM,CAc7B,CAAC;AAEF,eAAe,IAAI,CAAC;AACpB,KAAK,KAAK,GAAG,QAAQ,CAAC,OAAO,MAAM,CAAC,CAAC;AA6GrC,gFAAgF;AAChF,eAAO,MAAM,OAAO,EAAE,KAMrB,CAAC;AAEF,yEAAyE;AACzE,eAAO,MAAM,cAAc,EAAE,KAM5B,CAAC;AAEF,oEAAoE;AACpE,eAAO,MAAM,WAAW,EAAE,KAMzB,CAAC;AAEF,iEAAiE;AACjE,eAAO,MAAM,YAAY,EAAE,KAM1B,CAAC;AAEF,yDAAyD;AACzD,eAAO,MAAM,KAAK,EAAE,KAMnB,CAAC;AAEF,4DAA4D;AAC5D,eAAO,MAAM,iBAAiB,EAAE,KAM/B,CAAC;AAEF,6DAA6D;AAC7D,eAAO,MAAM,KAAK,EAAE,KAMnB,CAAC"}