@shepai/cli 1.83.0 → 1.84.0

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 (147) hide show
  1. package/apis/json-schema/Feature.yaml +5 -0
  2. package/dist/packages/core/src/application/use-cases/agents/reject-agent-run.use-case.d.ts.map +1 -1
  3. package/dist/packages/core/src/application/use-cases/agents/reject-agent-run.use-case.js +3 -0
  4. package/dist/src/presentation/web/app/actions/get-feature-phase-timings.d.ts +6 -0
  5. package/dist/src/presentation/web/app/actions/get-feature-phase-timings.d.ts.map +1 -1
  6. package/dist/src/presentation/web/app/actions/get-feature-phase-timings.js +26 -1
  7. package/dist/src/presentation/web/components/common/feature-drawer-tabs/activity-tab.d.ts +3 -2
  8. package/dist/src/presentation/web/components/common/feature-drawer-tabs/activity-tab.d.ts.map +1 -1
  9. package/dist/src/presentation/web/components/common/feature-drawer-tabs/activity-tab.js +29 -6
  10. package/dist/src/presentation/web/components/common/feature-drawer-tabs/activity-tab.stories.d.ts +2 -0
  11. package/dist/src/presentation/web/components/common/feature-drawer-tabs/activity-tab.stories.d.ts.map +1 -1
  12. package/dist/src/presentation/web/components/common/feature-drawer-tabs/activity-tab.stories.js +72 -0
  13. package/dist/src/presentation/web/components/common/feature-drawer-tabs/feature-drawer-tabs.d.ts.map +1 -1
  14. package/dist/src/presentation/web/components/common/feature-drawer-tabs/feature-drawer-tabs.js +2 -2
  15. package/dist/tsconfig.build.tsbuildinfo +1 -1
  16. package/package.json +1 -1
  17. package/web/.next/BUILD_ID +1 -1
  18. package/web/.next/build-manifest.json +2 -2
  19. package/web/.next/fallback-build-manifest.json +2 -2
  20. package/web/.next/prerender-manifest.json +3 -3
  21. package/web/.next/required-server-files.js +1 -1
  22. package/web/.next/required-server-files.json +1 -1
  23. package/web/.next/server/app/(dashboard)/@drawer/create/page/server-reference-manifest.json +18 -18
  24. package/web/.next/server/app/(dashboard)/@drawer/create/page.js.nft.json +1 -1
  25. package/web/.next/server/app/(dashboard)/@drawer/create/page_client-reference-manifest.js +1 -1
  26. package/web/.next/server/app/(dashboard)/@drawer/feature/[featureId]/page/server-reference-manifest.json +21 -21
  27. package/web/.next/server/app/(dashboard)/@drawer/feature/[featureId]/page.js +1 -1
  28. package/web/.next/server/app/(dashboard)/@drawer/feature/[featureId]/page.js.nft.json +1 -1
  29. package/web/.next/server/app/(dashboard)/@drawer/feature/[featureId]/page_client-reference-manifest.js +1 -1
  30. package/web/.next/server/app/(dashboard)/@drawer/repository/[repositoryId]/page/server-reference-manifest.json +14 -14
  31. package/web/.next/server/app/(dashboard)/@drawer/repository/[repositoryId]/page.js.nft.json +1 -1
  32. package/web/.next/server/app/(dashboard)/@drawer/repository/[repositoryId]/page_client-reference-manifest.js +1 -1
  33. package/web/.next/server/app/(dashboard)/create/page/server-reference-manifest.json +18 -18
  34. package/web/.next/server/app/(dashboard)/create/page.js.nft.json +1 -1
  35. package/web/.next/server/app/(dashboard)/create/page_client-reference-manifest.js +1 -1
  36. package/web/.next/server/app/(dashboard)/feature/[featureId]/page/server-reference-manifest.json +21 -21
  37. package/web/.next/server/app/(dashboard)/feature/[featureId]/page.js +1 -1
  38. package/web/.next/server/app/(dashboard)/feature/[featureId]/page.js.nft.json +1 -1
  39. package/web/.next/server/app/(dashboard)/feature/[featureId]/page_client-reference-manifest.js +1 -1
  40. package/web/.next/server/app/(dashboard)/page/server-reference-manifest.json +14 -14
  41. package/web/.next/server/app/(dashboard)/page.js.nft.json +1 -1
  42. package/web/.next/server/app/(dashboard)/page_client-reference-manifest.js +1 -1
  43. package/web/.next/server/app/(dashboard)/repository/[repositoryId]/page/server-reference-manifest.json +14 -14
  44. package/web/.next/server/app/(dashboard)/repository/[repositoryId]/page.js.nft.json +1 -1
  45. package/web/.next/server/app/(dashboard)/repository/[repositoryId]/page_client-reference-manifest.js +1 -1
  46. package/web/.next/server/app/_global-error.html +2 -2
  47. package/web/.next/server/app/_global-error.rsc +1 -1
  48. package/web/.next/server/app/_global-error.segments/__PAGE__.segment.rsc +1 -1
  49. package/web/.next/server/app/_global-error.segments/_full.segment.rsc +1 -1
  50. package/web/.next/server/app/_global-error.segments/_head.segment.rsc +1 -1
  51. package/web/.next/server/app/_global-error.segments/_index.segment.rsc +1 -1
  52. package/web/.next/server/app/_global-error.segments/_tree.segment.rsc +1 -1
  53. package/web/.next/server/app/_not-found/page/server-reference-manifest.json +1 -1
  54. package/web/.next/server/app/_not-found/page_client-reference-manifest.js +1 -1
  55. package/web/.next/server/app/api/dialog/pick-files/route.js +1 -1
  56. package/web/.next/server/app/api/dialog/pick-files/route.js.nft.json +1 -1
  57. package/web/.next/server/app/settings/page/server-reference-manifest.json +5 -5
  58. package/web/.next/server/app/settings/page.js.nft.json +1 -1
  59. package/web/.next/server/app/settings/page_client-reference-manifest.js +1 -1
  60. package/web/.next/server/app/skills/page/server-reference-manifest.json +6 -6
  61. package/web/.next/server/app/skills/page.js +3 -2
  62. package/web/.next/server/app/skills/page.js.nft.json +1 -1
  63. package/web/.next/server/app/skills/page_client-reference-manifest.js +1 -1
  64. package/web/.next/server/app/tools/page/server-reference-manifest.json +6 -6
  65. package/web/.next/server/app/tools/page_client-reference-manifest.js +1 -1
  66. package/web/.next/server/app/version/page/server-reference-manifest.json +1 -1
  67. package/web/.next/server/app/version/page_client-reference-manifest.js +1 -1
  68. package/web/.next/server/chunks/{[root-of-the-server]__a6bf88cc._.js → [root-of-the-server]__332c8d91._.js} +2 -2
  69. package/web/.next/server/chunks/ssr/744ca_web_components_common_control-center-drawer_create-drawer-client_tsx_5e26fc0a._.js +1 -1
  70. package/web/.next/server/chunks/ssr/744ca_web_components_common_control-center-drawer_create-drawer-client_tsx_5e26fc0a._.js.map +1 -1
  71. package/web/.next/server/chunks/ssr/8ba4b_server_app_(dashboard)_@drawer_repository_[repositoryId]_page_actions_da7eef33.js +1 -1
  72. package/web/.next/server/chunks/ssr/8ba4b_server_app_(dashboard)_@drawer_repository_[repositoryId]_page_actions_da7eef33.js.map +1 -1
  73. package/web/.next/server/chunks/ssr/8ba4b_server_app_(dashboard)_repository_[repositoryId]_page_actions_0a9251aa.js +1 -1
  74. package/web/.next/server/chunks/ssr/8ba4b_server_app_(dashboard)_repository_[repositoryId]_page_actions_0a9251aa.js.map +1 -1
  75. package/web/.next/server/chunks/ssr/90b01_js-yaml_dist_js-yaml_mjs_c897fb57._.js +3 -0
  76. package/web/.next/server/chunks/ssr/90b01_js-yaml_dist_js-yaml_mjs_c897fb57._.js.map +1 -0
  77. package/web/.next/server/chunks/ssr/[root-of-the-server]__11033878._.js +1 -1
  78. package/web/.next/server/chunks/ssr/[root-of-the-server]__11033878._.js.map +1 -1
  79. package/web/.next/server/chunks/ssr/[root-of-the-server]__17143953._.js +3 -0
  80. package/web/.next/server/chunks/ssr/[root-of-the-server]__17143953._.js.map +1 -0
  81. package/web/.next/server/chunks/ssr/[root-of-the-server]__357d99f9._.js +1 -1
  82. package/web/.next/server/chunks/ssr/[root-of-the-server]__4be9a9bb._.js +1 -1
  83. package/web/.next/server/chunks/ssr/[root-of-the-server]__5d87af2e._.js +1 -1
  84. package/web/.next/server/chunks/ssr/[root-of-the-server]__9de266fa._.js +3 -0
  85. package/web/.next/server/chunks/ssr/[root-of-the-server]__9de266fa._.js.map +1 -0
  86. package/web/.next/server/chunks/ssr/[root-of-the-server]__aad040c0._.js +1 -1
  87. package/web/.next/server/chunks/ssr/[root-of-the-server]__aad040c0._.js.map +1 -1
  88. package/web/.next/server/chunks/ssr/[root-of-the-server]__b3a4cef4._.js +1 -1
  89. package/web/.next/server/chunks/ssr/[root-of-the-server]__b3a4cef4._.js.map +1 -1
  90. package/web/.next/server/chunks/ssr/[root-of-the-server]__f0d8d054._.js +2 -2
  91. package/web/.next/server/chunks/ssr/[root-of-the-server]__fdc75809._.js +1 -1
  92. package/web/.next/server/chunks/ssr/[root-of-the-server]__fdc75809._.js.map +1 -1
  93. package/web/.next/server/chunks/ssr/_0387eb83._.js +3 -0
  94. package/web/.next/server/chunks/ssr/{_1f7387a5._.js.map → _0387eb83._.js.map} +1 -1
  95. package/web/.next/server/chunks/ssr/_1e3cf73b._.js +1 -1
  96. package/web/.next/server/chunks/ssr/_1e3cf73b._.js.map +1 -1
  97. package/web/.next/server/chunks/ssr/{_1c1bf992._.js → _3785d5be._.js} +2 -2
  98. package/web/.next/server/chunks/ssr/{_1c1bf992._.js.map → _3785d5be._.js.map} +1 -1
  99. package/web/.next/server/chunks/ssr/_3a4c94e3._.js +1 -1
  100. package/web/.next/server/chunks/ssr/_3a4c94e3._.js.map +1 -1
  101. package/web/.next/server/chunks/ssr/_63868199._.js +1 -1
  102. package/web/.next/server/chunks/ssr/_63868199._.js.map +1 -1
  103. package/web/.next/server/chunks/ssr/{_51505c5a._.js → _67dd9041._.js} +2 -2
  104. package/web/.next/server/chunks/ssr/{_51505c5a._.js.map → _67dd9041._.js.map} +1 -1
  105. package/web/.next/server/chunks/ssr/_8dacd1e7._.js +1 -1
  106. package/web/.next/server/chunks/ssr/_8dacd1e7._.js.map +1 -1
  107. package/web/.next/server/chunks/ssr/_c3a8bcb1._.js +1 -1
  108. package/web/.next/server/chunks/ssr/_c3a8bcb1._.js.map +1 -1
  109. package/web/.next/server/chunks/ssr/b1a17_presentation_web_components_features_settings_settings-page-client_tsx_6ed9d5f8._.js +1 -1
  110. package/web/.next/server/chunks/ssr/b1a17_presentation_web_components_features_settings_settings-page-client_tsx_6ed9d5f8._.js.map +1 -1
  111. package/web/.next/server/chunks/ssr/src_presentation_web__next-internal_server_app_(dashboard)_page_actions_021a05f2.js +1 -1
  112. package/web/.next/server/chunks/ssr/src_presentation_web__next-internal_server_app_(dashboard)_page_actions_021a05f2.js.map +1 -1
  113. package/web/.next/server/chunks/ssr/src_presentation_web__next-internal_server_app_skills_page_actions_1fa8042e.js +1 -1
  114. package/web/.next/server/chunks/ssr/src_presentation_web__next-internal_server_app_skills_page_actions_1fa8042e.js.map +1 -1
  115. package/web/.next/server/chunks/ssr/src_presentation_web__next-internal_server_app_tools_page_actions_24684200.js +1 -1
  116. package/web/.next/server/chunks/ssr/src_presentation_web__next-internal_server_app_tools_page_actions_24684200.js.map +1 -1
  117. package/web/.next/server/chunks/ssr/src_presentation_web_c4348b8a._.js +2 -2
  118. package/web/.next/server/chunks/ssr/src_presentation_web_c4348b8a._.js.map +1 -1
  119. package/web/.next/server/chunks/ssr/src_presentation_web_components_features_control-center_7ac3562e._.js +1 -1
  120. package/web/.next/server/chunks/ssr/src_presentation_web_components_features_control-center_7ac3562e._.js.map +1 -1
  121. package/web/.next/server/chunks/ssr/src_presentation_web_e4510d10._.js +2 -2
  122. package/web/.next/server/chunks/ssr/src_presentation_web_e4510d10._.js.map +1 -1
  123. package/web/.next/server/pages/500.html +2 -2
  124. package/web/.next/server/server-reference-manifest.js +1 -1
  125. package/web/.next/server/server-reference-manifest.json +28 -28
  126. package/web/.next/static/chunks/{2d4cc4000f402d7f.js → 48060fe38d7b8432.js} +1 -1
  127. package/web/.next/static/chunks/{996902d74a48276d.js → 4de791d92c72ae58.js} +1 -1
  128. package/web/.next/static/chunks/6b4620c8b57a0683.js +1 -0
  129. package/web/.next/static/chunks/{0543f7be533ecb32.js → 6d0190cd8484320c.js} +1 -1
  130. package/web/.next/static/chunks/{6e77201e99d50131.js → 6f0622cb06faf358.js} +1 -1
  131. package/web/.next/static/chunks/{a453628f546647a7.js → 7e92542991a14568.js} +1 -1
  132. package/web/.next/static/chunks/{d9829b5681886395.js → a56b3854d2169db0.js} +1 -1
  133. package/web/.next/static/chunks/ae01d2be1d0bad47.css +2 -0
  134. package/web/.next/static/chunks/{d1e04a49da8d02f9.js → d00436ccde44862f.js} +1 -1
  135. package/web/.next/static/chunks/{34f6df8ccffe5d52.js → de2515446676e0ae.js} +1 -1
  136. package/web/.next/static/chunks/{ed0297ac085a1f85.js → df0b93fbb9b512e6.js} +1 -1
  137. package/web/.next/server/chunks/ssr/_1f7387a5._.js +0 -3
  138. package/web/.next/server/chunks/ssr/src_presentation_web_7efa14ca._.js +0 -3
  139. package/web/.next/server/chunks/ssr/src_presentation_web_7efa14ca._.js.map +0 -1
  140. package/web/.next/server/chunks/ssr/src_presentation_web_b59d79db._.js +0 -3
  141. package/web/.next/server/chunks/ssr/src_presentation_web_b59d79db._.js.map +0 -1
  142. package/web/.next/static/chunks/1e5cf3d452bf9f47.js +0 -1
  143. package/web/.next/static/chunks/96bab6d3820504f3.css +0 -2
  144. /package/web/.next/server/chunks/{[root-of-the-server]__a6bf88cc._.js.map → [root-of-the-server]__332c8d91._.js.map} +0 -0
  145. /package/web/.next/static/{W2fL0P9VKhEH6f0RCcR8s → 7IllAyl6ItP_HYk-RfUYQ}/_buildManifest.js +0 -0
  146. /package/web/.next/static/{W2fL0P9VKhEH6f0RCcR8s → 7IllAyl6ItP_HYk-RfUYQ}/_clientMiddlewareManifest.json +0 -0
  147. /package/web/.next/static/{W2fL0P9VKhEH6f0RCcR8s → 7IllAyl6ItP_HYk-RfUYQ}/_ssgManifest.js +0 -0
@@ -45,6 +45,10 @@ properties:
45
45
  repositoryId:
46
46
  $ref: UUID.yaml
47
47
  description: ID of the Repository entity this feature belongs to
48
+ fast:
49
+ type: boolean
50
+ default: false
51
+ description: When true, SDLC phases were skipped and the feature was implemented directly from the prompt
48
52
  push:
49
53
  type: boolean
50
54
  default: false
@@ -75,6 +79,7 @@ required:
75
79
  - lifecycle
76
80
  - messages
77
81
  - relatedArtifacts
82
+ - fast
78
83
  - push
79
84
  - openPr
80
85
  - approvalGates
@@ -1 +1 @@
1
- {"version":3,"file":"reject-agent-run.use-case.d.ts","sourceRoot":"","sources":["../../../../../../../packages/core/src/application/use-cases/agents/reject-agent-run.use-case.ts"],"names":[],"mappings":"AAAA;;;;;;GAMG;AAMH,OAAO,KAAK,EAAE,mBAAmB,EAAE,MAAM,6DAA6D,CAAC;AACvG,OAAO,KAAK,EAAE,2BAA2B,EAAE,MAAM,8DAA8D,CAAC;AAChH,OAAO,KAAK,EAAE,sBAAsB,EAAE,MAAM,gEAAgE,CAAC;AAC7G,OAAO,KAAK,EAAE,kBAAkB,EAAE,MAAM,iEAAiE,CAAC;AAS1G,qBACa,qBAAqB;IAG9B,OAAO,CAAC,QAAQ,CAAC,kBAAkB;IAEnC,OAAO,CAAC,QAAQ,CAAC,cAAc;IAE/B,OAAO,CAAC,QAAQ,CAAC,iBAAiB;IAElC,OAAO,CAAC,QAAQ,CAAC,qBAAqB;gBANrB,kBAAkB,EAAE,mBAAmB,EAEvC,cAAc,EAAE,2BAA2B,EAE3C,iBAAiB,EAAE,kBAAkB,EAErC,qBAAqB,EAAE,sBAAsB;IAG1D,OAAO,CACX,EAAE,EAAE,MAAM,EACV,QAAQ,EAAE,MAAM,GACf,OAAO,CAAC;QACT,QAAQ,EAAE,OAAO,CAAC;QAClB,MAAM,EAAE,MAAM,CAAC;QACf,SAAS,CAAC,EAAE,MAAM,CAAC;QACnB,gBAAgB,CAAC,EAAE,OAAO,CAAC;KAC5B,CAAC;CAgHH"}
1
+ {"version":3,"file":"reject-agent-run.use-case.d.ts","sourceRoot":"","sources":["../../../../../../../packages/core/src/application/use-cases/agents/reject-agent-run.use-case.ts"],"names":[],"mappings":"AAAA;;;;;;GAMG;AAMH,OAAO,KAAK,EAAE,mBAAmB,EAAE,MAAM,6DAA6D,CAAC;AACvG,OAAO,KAAK,EAAE,2BAA2B,EAAE,MAAM,8DAA8D,CAAC;AAChH,OAAO,KAAK,EAAE,sBAAsB,EAAE,MAAM,gEAAgE,CAAC;AAC7G,OAAO,KAAK,EAAE,kBAAkB,EAAE,MAAM,iEAAiE,CAAC;AAU1G,qBACa,qBAAqB;IAG9B,OAAO,CAAC,QAAQ,CAAC,kBAAkB;IAEnC,OAAO,CAAC,QAAQ,CAAC,cAAc;IAE/B,OAAO,CAAC,QAAQ,CAAC,iBAAiB;IAElC,OAAO,CAAC,QAAQ,CAAC,qBAAqB;gBANrB,kBAAkB,EAAE,mBAAmB,EAEvC,cAAc,EAAE,2BAA2B,EAE3C,iBAAiB,EAAE,kBAAkB,EAErC,qBAAqB,EAAE,sBAAsB;IAG1D,OAAO,CACX,EAAE,EAAE,MAAM,EACV,QAAQ,EAAE,MAAM,GACf,OAAO,CAAC;QACT,QAAQ,EAAE,OAAO,CAAC;QAClB,MAAM,EAAE,MAAM,CAAC;QACf,SAAS,CAAC,EAAE,MAAM,CAAC;QACnB,gBAAgB,CAAC,EAAE,OAAO,CAAC;KAC5B,CAAC;CAmHH"}
@@ -23,6 +23,7 @@ import { readFileSync } from 'node:fs';
23
23
  import { join } from 'node:path';
24
24
  import { AgentRunStatus } from '../../../domain/generated/output.js';
25
25
  import { writeSpecFileAtomic } from '../../../infrastructure/services/agents/feature-agent/nodes/node-helpers.js';
26
+ import { recordLifecycleEvent } from '../../../infrastructure/services/agents/feature-agent/phase-timing-context.js';
26
27
  import { computeWorktreePath } from '../../../infrastructure/services/ide-launchers/compute-worktree-path.js';
27
28
  let RejectAgentRunUseCase = class RejectAgentRunUseCase {
28
29
  agentRunRepository;
@@ -101,6 +102,8 @@ let RejectAgentRunUseCase = class RejectAgentRunUseCase {
101
102
  catch {
102
103
  // Non-fatal
103
104
  }
105
+ // Record rejected lifecycle event
106
+ await recordLifecycleEvent('run:rejected', id, this.phaseTimingRepository);
104
107
  // Spawn worker with rejection payload
105
108
  const rejectionPayload = {
106
109
  rejected: true,
@@ -7,8 +7,14 @@ export interface PhaseTimingData {
7
7
  waitingApprovalAt?: string;
8
8
  approvalWaitMs?: number;
9
9
  }
10
+ export interface RejectionFeedbackData {
11
+ iteration: number;
12
+ message: string;
13
+ phase?: string;
14
+ }
10
15
  type GetPhaseTimingsResult = {
11
16
  timings: PhaseTimingData[];
17
+ rejectionFeedback: RejectionFeedbackData[];
12
18
  } | {
13
19
  error: string;
14
20
  };
@@ -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":"AAKA,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;CACzB;AAED,KAAK,qBAAqB,GAAG;IAAE,OAAO,EAAE,eAAe,EAAE,CAAA;CAAE,GAAG;IAAE,KAAK,EAAE,MAAM,CAAA;CAAE,CAAC;AAEhF,wBAAsB,sBAAsB,CAAC,SAAS,EAAE,MAAM,GAAG,OAAO,CAAC,qBAAqB,CAAC,CAwB9F"}
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;CACzB;AAED,MAAM,WAAW,qBAAqB;IACpC,SAAS,EAAE,MAAM,CAAC;IAClB,OAAO,EAAE,MAAM,CAAC;IAChB,KAAK,CAAC,EAAE,MAAM,CAAC;CAChB;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,CA2B9F"}
@@ -16,10 +16,35 @@ export async function getFeaturePhaseTimings(featureId) {
16
16
  waitingApprovalAt: t.waitingApprovalAt,
17
17
  approvalWaitMs: t.approvalWaitMs != null ? Number(t.approvalWaitMs) : undefined,
18
18
  }));
19
- return { timings };
19
+ // Read rejection feedback from spec.yaml
20
+ const rejectionFeedback = await readRejectionFeedback(featureId);
21
+ return { timings, rejectionFeedback };
20
22
  }
21
23
  catch (error) {
22
24
  const message = error instanceof Error ? error.message : 'Failed to load phase timings';
23
25
  return { error: message };
24
26
  }
25
27
  }
28
+ async function readRejectionFeedback(featureId) {
29
+ try {
30
+ const featureRepo = resolve('IFeatureRepository');
31
+ const feature = await featureRepo.findById(featureId);
32
+ if (!feature?.specPath)
33
+ return [];
34
+ const { readFileSync } = await import('node:fs');
35
+ const { join } = await import('node:path');
36
+ const yaml = (await import('js-yaml')).default;
37
+ const specContent = readFileSync(join(feature.specPath, 'spec.yaml'), 'utf-8');
38
+ const spec = yaml.load(specContent);
39
+ if (!Array.isArray(spec?.rejectionFeedback))
40
+ return [];
41
+ return spec.rejectionFeedback.map((entry) => ({
42
+ iteration: Number(entry.iteration ?? 1),
43
+ message: String(entry.message ?? ''),
44
+ phase: entry.phase ? String(entry.phase) : undefined,
45
+ }));
46
+ }
47
+ catch {
48
+ return [];
49
+ }
50
+ }
@@ -1,8 +1,9 @@
1
- import type { PhaseTimingData } from '../../../app/actions/get-feature-phase-timings.js';
1
+ import type { PhaseTimingData, RejectionFeedbackData } from '../../../app/actions/get-feature-phase-timings.js';
2
2
  export interface ActivityTabProps {
3
3
  timings: PhaseTimingData[] | null;
4
4
  loading: boolean;
5
5
  error: string | null;
6
+ rejectionFeedback?: RejectionFeedbackData[];
6
7
  }
7
- export declare function ActivityTab({ timings, loading, error }: ActivityTabProps): import("react/jsx-runtime").JSX.Element;
8
+ export declare function ActivityTab({ timings, loading, error, rejectionFeedback }: ActivityTabProps): import("react/jsx-runtime").JSX.Element;
8
9
  //# sourceMappingURL=activity-tab.d.ts.map
@@ -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,EAAE,eAAe,EAAE,MAAM,yCAAyC,CAAC;AAE/E,MAAM,WAAW,gBAAgB;IAC/B,OAAO,EAAE,eAAe,EAAE,GAAG,IAAI,CAAC;IAClC,OAAO,EAAE,OAAO,CAAC;IACjB,KAAK,EAAE,MAAM,GAAG,IAAI,CAAC;CACtB;AA+CD,wBAAgB,WAAW,CAAC,EAAE,OAAO,EAAE,OAAO,EAAE,KAAK,EAAE,EAAE,gBAAgB,2CA0DxE"}
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;AAEjD,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;AAsED,wBAAgB,WAAW,CAAC,EAAE,OAAO,EAAE,OAAO,EAAE,KAAK,EAAE,iBAAiB,EAAE,EAAE,gBAAgB,2CA8D3F"}
@@ -16,6 +16,7 @@ const LIFECYCLE_EVENTS = {
16
16
  'run:failed': { label: 'failed', colorClass: 'text-red-600' },
17
17
  'run:stopped': { label: 'stopped', colorClass: 'text-amber-600' },
18
18
  'run:crashed': { label: 'crashed', colorClass: 'text-red-600' },
19
+ 'run:rejected': { label: 'rejected', colorClass: 'text-orange-600' },
19
20
  };
20
21
  function isLifecycleEvent(phase) {
21
22
  return phase.startsWith('run:');
@@ -36,7 +37,25 @@ function groupTimingsByRun(timings) {
36
37
  }
37
38
  return groups;
38
39
  }
39
- export function ActivityTab({ timings, loading, error }) {
40
+ /**
41
+ * Map each run:rejected timing entry to its rejection feedback message.
42
+ * Matches by sequential order: 1st rejected event → 1st feedback entry, etc.
43
+ */
44
+ function buildRejectionMessageMap(timings, feedback) {
45
+ const map = new Map();
46
+ if (!feedback?.length)
47
+ return map;
48
+ let rejectionIdx = 0;
49
+ for (const t of timings) {
50
+ if (t.phase === 'run:rejected' && rejectionIdx < feedback.length) {
51
+ const key = `${t.agentRunId}-${t.phase}-${t.startedAt}`;
52
+ map.set(key, feedback[rejectionIdx].message);
53
+ rejectionIdx++;
54
+ }
55
+ }
56
+ return map;
57
+ }
58
+ export function ActivityTab({ timings, loading, error, rejectionFeedback }) {
40
59
  if (loading) {
41
60
  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" }) }));
42
61
  }
@@ -48,25 +67,29 @@ export function ActivityTab({ timings, loading, error }) {
48
67
  }
49
68
  const nodeTimings = timings.filter((t) => !isLifecycleEvent(t.phase));
50
69
  const maxDurationMs = Math.max(...nodeTimings.map((t) => t.durationMs ?? 0), ...nodeTimings.map((t) => t.approvalWaitMs ?? 0), 0);
70
+ // Build a map from rejection index to feedback message
71
+ const rejectionMessages = buildRejectionMessageMap(timings, rejectionFeedback);
51
72
  const groups = groupTimingsByRun(timings);
52
73
  const multiRun = groups.length > 1;
53
74
  const totalExecMs = nodeTimings.reduce((sum, t) => sum + (t.durationMs ?? 0), 0);
54
75
  const totalWaitMs = nodeTimings.reduce((sum, t) => sum + (t.approvalWaitMs ?? 0), 0);
55
- 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: groups.map((group, groupIdx) => (_jsx(RunGroup, { group: group, groupIdx: groupIdx, multiRun: multiRun, maxDurationMs: maxDurationMs }, group.runId))) }), totalExecMs > 0 ? (_jsx(SummaryTotals, { totalExecMs: totalExecMs, totalWaitMs: totalWaitMs })) : null] }));
76
+ 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: groups.map((group, groupIdx) => (_jsx(RunGroup, { group: group, groupIdx: groupIdx, multiRun: multiRun, maxDurationMs: maxDurationMs, rejectionMessages: rejectionMessages }, group.runId))) }), totalExecMs > 0 ? (_jsx(SummaryTotals, { totalExecMs: totalExecMs, totalWaitMs: totalWaitMs })) : null] }));
56
77
  }
57
- function RunGroup({ group, groupIdx, multiRun, maxDurationMs, }) {
78
+ function RunGroup({ group, groupIdx, multiRun, maxDurationMs, rejectionMessages, }) {
58
79
  return (_jsxs("div", { className: "flex flex-col gap-1.5", children: [multiRun ? (_jsxs("div", { className: "text-muted-foreground text-xs font-medium", children: ["Run #", groupIdx + 1] })) : null, group.timings.map((t) => {
59
80
  if (isLifecycleEvent(t.phase)) {
60
- return _jsx(LifecycleEventRow, { timing: t }, `${t.agentRunId}-${t.phase}-${t.startedAt}`);
81
+ const key = `${t.agentRunId}-${t.phase}-${t.startedAt}`;
82
+ const message = t.phase === 'run:rejected' ? rejectionMessages.get(key) : undefined;
83
+ return _jsx(LifecycleEventRow, { timing: t, message: message }, key);
61
84
  }
62
85
  return (_jsx(NodeTimingRow, { timing: t, maxDurationMs: maxDurationMs }, `${t.agentRunId}-${t.phase}-${t.startedAt}`));
63
86
  })] }));
64
87
  }
65
- function LifecycleEventRow({ timing }) {
88
+ function LifecycleEventRow({ timing, message }) {
66
89
  const event = LIFECYCLE_EVENTS[timing.phase];
67
90
  if (!event)
68
91
  return null;
69
- return (_jsx("div", { className: `text-xs ${event.colorClass}`, children: _jsx("span", { children: event.label }) }));
92
+ 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] }));
70
93
  }
71
94
  function NodeTimingRow({ timing, maxDurationMs, }) {
72
95
  const label = timing.phase.includes(':')
@@ -15,6 +15,8 @@ export declare const Loading: Story;
15
15
  export declare const Empty: Story;
16
16
  /** Error state — inline error message. */
17
17
  export declare const Error: Story;
18
+ /** Rejection — shows rejected lifecycle event with user feedback text. */
19
+ export declare const WithRejection: Story;
18
20
  /** Approval wait indicators — phases with approval wait sub-rows. */
19
21
  export declare const WithApprovalWaits: Story;
20
22
  //# sourceMappingURL=activity-tab.stories.d.ts.map
@@ -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,qEAAqE;AACrE,eAAO,MAAM,iBAAiB,EAAE,KAgC/B,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;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,qEAAqE;AACrE,eAAO,MAAM,iBAAiB,EAAE,KAgC/B,CAAC"}
@@ -216,6 +216,78 @@ export const Error = {
216
216
  error: 'Failed to load phase timings. Please try again.',
217
217
  },
218
218
  };
219
+ /** Rejection — shows rejected lifecycle event with user feedback text. */
220
+ export const WithRejection = {
221
+ args: {
222
+ timings: [
223
+ {
224
+ agentRunId: 'run-1',
225
+ phase: 'run:started',
226
+ startedAt: '2025-01-15T10:00:00Z',
227
+ durationMs: 0,
228
+ },
229
+ {
230
+ agentRunId: 'run-1',
231
+ phase: 'analyze',
232
+ startedAt: '2025-01-15T10:00:01Z',
233
+ completedAt: '2025-01-15T10:00:15Z',
234
+ durationMs: 14000,
235
+ },
236
+ {
237
+ agentRunId: 'run-1',
238
+ phase: 'requirements',
239
+ startedAt: '2025-01-15T10:00:15Z',
240
+ completedAt: '2025-01-15T10:01:45Z',
241
+ durationMs: 90000,
242
+ waitingApprovalAt: '2025-01-15T10:01:00Z',
243
+ approvalWaitMs: 30000,
244
+ },
245
+ {
246
+ agentRunId: 'run-1',
247
+ phase: 'run:rejected',
248
+ startedAt: '2025-01-15T10:01:45Z',
249
+ durationMs: 0,
250
+ },
251
+ {
252
+ agentRunId: 'run-1',
253
+ phase: 'run:resumed',
254
+ startedAt: '2025-01-15T10:02:00Z',
255
+ durationMs: 0,
256
+ },
257
+ {
258
+ agentRunId: 'run-1',
259
+ phase: 'requirements:2',
260
+ startedAt: '2025-01-15T10:02:01Z',
261
+ completedAt: '2025-01-15T10:03:30Z',
262
+ durationMs: 89000,
263
+ waitingApprovalAt: '2025-01-15T10:03:00Z',
264
+ approvalWaitMs: 15000,
265
+ },
266
+ {
267
+ agentRunId: 'run-1',
268
+ phase: 'research',
269
+ startedAt: '2025-01-15T10:03:30Z',
270
+ completedAt: '2025-01-15T10:05:00Z',
271
+ durationMs: 90000,
272
+ },
273
+ {
274
+ agentRunId: 'run-1',
275
+ phase: 'run:completed',
276
+ startedAt: '2025-01-15T10:05:00Z',
277
+ durationMs: 0,
278
+ },
279
+ ],
280
+ rejectionFeedback: [
281
+ {
282
+ iteration: 1,
283
+ message: 'The requirements are missing error handling for edge cases',
284
+ phase: 'requirements',
285
+ },
286
+ ],
287
+ loading: false,
288
+ error: null,
289
+ },
290
+ };
219
291
  /** Approval wait indicators — phases with approval wait sub-rows. */
220
292
  export const WithApprovalWaits = {
221
293
  args: {
@@ -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":"AASA,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;AAaxE,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;IAG3B,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,KAAK,IAAI,CAAC;IACzC,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,KAAK,IAAI,CAAC;IAC1C,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,KAAK,IAAI,CAAC;IAC3C,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;AAmBD,wBAAgB,iBAAiB,CAAC,EAChC,WAAW,EACX,SAAS,EACT,UAAU,EACV,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,2CA2MxB"}
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":"AAYA,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;AAaxE,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;IAG3B,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,KAAK,IAAI,CAAC;IACzC,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,KAAK,IAAI,CAAC;IAC1C,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,KAAK,IAAI,CAAC;IAC3C,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,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,2CA4MxB"}
@@ -51,7 +51,7 @@ async function fetchActivity(featureId) {
51
51
  const result = await getFeaturePhaseTimings(featureId);
52
52
  if ('error' in result)
53
53
  throw new Error(result.error);
54
- return result.timings;
54
+ return { timings: result.timings, rejectionFeedback: result.rejectionFeedback };
55
55
  }
56
56
  async function fetchPlan(featureId) {
57
57
  const result = await getFeaturePlan(featureId);
@@ -115,7 +115,7 @@ export function FeatureDrawerTabs({ featureNode, featureId, initialTab, prdData,
115
115
  fetchTab(tab);
116
116
  }
117
117
  }, [fetchTab]);
118
- return (_jsx("div", { className: "flex min-h-0 flex-1 flex-col", children: _jsxs(Tabs, { value: activeTab, onValueChange: handleTabChange, className: "flex min-h-0 flex-1 flex-col", children: [_jsx("div", { className: "shrink-0 overflow-x-auto px-4 pt-4", children: _jsx(TabsList, { className: "flex w-full", children: visibleTabDefs.map((tab) => (_jsx(TabsTrigger, { value: tab.key, className: "flex-1", children: tab.label }, tab.key))) }) }), _jsx(TabsContent, { value: "overview", className: "mt-0 flex-1 overflow-y-auto", children: _jsx(OverviewTab, { data: featureNode }) }), _jsx(TabsContent, { value: "activity", className: "mt-0 flex-1 overflow-y-auto", children: _jsx(ActivityTab, { timings: tabs.activity.data, loading: tabs.activity.loading, error: tabs.activity.error }) }), _jsx(TabsContent, { value: "log", className: "mt-0 flex-1 overflow-hidden", children: _jsx(LogTab, { content: featureLogs.content, isConnected: featureLogs.isConnected, error: featureLogs.error }) }), _jsx(TabsContent, { value: "plan", className: "mt-0 flex-1 overflow-y-auto", children: _jsx(PlanTab, { plan: tabs.plan.data, loading: tabs.plan.loading, error: tabs.plan.error }) }), visibleTabs.includes('prd-review') ? (_jsx(TabsContent, { value: "prd-review", className: "mt-0 flex min-h-0 flex-1 flex-col", children: prdData ? (_jsx(PrdQuestionnaire, { data: prdData, selections: prdSelections ?? {}, onSelect: onPrdSelect ?? (() => undefined), onApprove: onPrdApprove ?? (() => undefined), onReject: onPrdReject, isProcessing: isPrdLoading, isRejecting: isRejecting, chatInput: chatInput, onChatInputChange: onChatInputChange })) : (_jsx("div", { className: "flex items-center justify-center p-8", children: _jsx(Loader2, { className: "text-muted-foreground h-6 w-6 animate-spin" }) })) })) : null, visibleTabs.includes('tech-decisions') ? (_jsx(TabsContent, { value: "tech-decisions", className: "mt-0 flex min-h-0 flex-1 flex-col", children: techData ? (_jsxs("div", { className: "flex min-h-0 flex-1 flex-col", children: [_jsx("div", { className: "flex-1 overflow-y-auto", children: _jsx(TechDecisionsContent, { data: techData }) }), _jsx(DrawerActionBarForTech, { onApprove: onTechApprove ?? (() => undefined), onReject: onTechReject, isProcessing: isTechLoading, isRejecting: isRejecting, chatInput: chatInput, onChatInputChange: onChatInputChange })] })) : (_jsx("div", { className: "flex items-center justify-center p-8", children: _jsx(Loader2, { className: "text-muted-foreground h-6 w-6 animate-spin" }) })) })) : null, visibleTabs.includes('product-decisions') ? (_jsx(TabsContent, { value: "product-decisions", className: "mt-0 flex-1 overflow-y-auto", children: productData === null ? (_jsx("div", { className: "flex items-center justify-center p-8", children: _jsx(Loader2, { className: "text-muted-foreground h-6 w-6 animate-spin" }) })) : productData ? (_jsx(ProductDecisionsSummary, { data: productData })) : (_jsx("p", { className: "text-muted-foreground p-4 text-center text-sm", children: "No product decisions available." })) })) : null, visibleTabs.includes('merge-review') ? (_jsx(TabsContent, { value: "merge-review", className: "mt-0 flex min-h-0 flex-1 flex-col", children: mergeData ? (_jsx(MergeReview, { data: mergeData, onApprove: onMergeApprove ?? (() => undefined), onReject: onMergeReject, isProcessing: isMergeLoading, isRejecting: isRejecting, chatInput: chatInput, onChatInputChange: onChatInputChange })) : (_jsx("div", { className: "flex items-center justify-center p-8", children: _jsx(Loader2, { className: "text-muted-foreground h-6 w-6 animate-spin" }) })) })) : null] }) }));
118
+ return (_jsx("div", { className: "flex min-h-0 flex-1 flex-col", children: _jsxs(Tabs, { value: activeTab, onValueChange: handleTabChange, className: "flex min-h-0 flex-1 flex-col", children: [_jsx("div", { className: "shrink-0 overflow-x-auto px-4 pt-4", children: _jsx(TabsList, { className: "flex w-full", children: visibleTabDefs.map((tab) => (_jsx(TabsTrigger, { value: tab.key, className: "flex-1", children: tab.label }, tab.key))) }) }), _jsx(TabsContent, { value: "overview", className: "mt-0 flex-1 overflow-y-auto", children: _jsx(OverviewTab, { data: featureNode }) }), _jsx(TabsContent, { value: "activity", className: "mt-0 flex-1 overflow-y-auto", children: _jsx(ActivityTab, { timings: tabs.activity.data?.timings ?? null, loading: tabs.activity.loading, error: tabs.activity.error, rejectionFeedback: tabs.activity.data?.rejectionFeedback }) }), _jsx(TabsContent, { value: "log", className: "mt-0 flex-1 overflow-hidden", children: _jsx(LogTab, { content: featureLogs.content, isConnected: featureLogs.isConnected, error: featureLogs.error }) }), _jsx(TabsContent, { value: "plan", className: "mt-0 flex-1 overflow-y-auto", children: _jsx(PlanTab, { plan: tabs.plan.data, loading: tabs.plan.loading, error: tabs.plan.error }) }), visibleTabs.includes('prd-review') ? (_jsx(TabsContent, { value: "prd-review", className: "mt-0 flex min-h-0 flex-1 flex-col", children: prdData ? (_jsx(PrdQuestionnaire, { data: prdData, selections: prdSelections ?? {}, onSelect: onPrdSelect ?? (() => undefined), onApprove: onPrdApprove ?? (() => undefined), onReject: onPrdReject, isProcessing: isPrdLoading, isRejecting: isRejecting, chatInput: chatInput, onChatInputChange: onChatInputChange })) : (_jsx("div", { className: "flex items-center justify-center p-8", children: _jsx(Loader2, { className: "text-muted-foreground h-6 w-6 animate-spin" }) })) })) : null, visibleTabs.includes('tech-decisions') ? (_jsx(TabsContent, { value: "tech-decisions", className: "mt-0 flex min-h-0 flex-1 flex-col", children: techData ? (_jsxs("div", { className: "flex min-h-0 flex-1 flex-col", children: [_jsx("div", { className: "flex-1 overflow-y-auto", children: _jsx(TechDecisionsContent, { data: techData }) }), _jsx(DrawerActionBarForTech, { onApprove: onTechApprove ?? (() => undefined), onReject: onTechReject, isProcessing: isTechLoading, isRejecting: isRejecting, chatInput: chatInput, onChatInputChange: onChatInputChange })] })) : (_jsx("div", { className: "flex items-center justify-center p-8", children: _jsx(Loader2, { className: "text-muted-foreground h-6 w-6 animate-spin" }) })) })) : null, visibleTabs.includes('product-decisions') ? (_jsx(TabsContent, { value: "product-decisions", className: "mt-0 flex-1 overflow-y-auto", children: productData === null ? (_jsx("div", { className: "flex items-center justify-center p-8", children: _jsx(Loader2, { className: "text-muted-foreground h-6 w-6 animate-spin" }) })) : productData ? (_jsx(ProductDecisionsSummary, { data: productData })) : (_jsx("p", { className: "text-muted-foreground p-4 text-center text-sm", children: "No product decisions available." })) })) : null, visibleTabs.includes('merge-review') ? (_jsx(TabsContent, { value: "merge-review", className: "mt-0 flex min-h-0 flex-1 flex-col", children: mergeData ? (_jsx(MergeReview, { data: mergeData, onApprove: onMergeApprove ?? (() => undefined), onReject: onMergeReject, isProcessing: isMergeLoading, isRejecting: isRejecting, chatInput: chatInput, onChatInputChange: onChatInputChange })) : (_jsx("div", { className: "flex items-center justify-center p-8", children: _jsx(Loader2, { className: "text-muted-foreground h-6 w-6 animate-spin" }) })) })) : null] }) }));
119
119
  }
120
120
  // ── Private helper ──────────────────────────────────────────────────────
121
121
  function DrawerActionBarForTech({ onApprove, onReject, isProcessing, isRejecting, chatInput, onChatInputChange, }) {