popilot 0.6.0 → 0.8.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 (165) hide show
  1. package/bin/cli.mjs +204 -2
  2. package/lib/doctor.mjs +38 -1
  3. package/lib/hydrate.mjs +15 -0
  4. package/lib/scaffold.mjs +5 -0
  5. package/lib/setup-wizard.mjs +35 -2
  6. package/package.json +1 -1
  7. package/scaffold/.context/project.yaml.example +19 -0
  8. package/scaffold/mcp-notification-server/package.json +18 -0
  9. package/scaffold/mcp-notification-server/src/index.ts +275 -0
  10. package/scaffold/mcp-notification-server/src/turso-client.ts +142 -0
  11. package/scaffold/mcp-notification-server/tsconfig.json +14 -0
  12. package/scaffold/mcp-pm/package.json +19 -0
  13. package/scaffold/mcp-pm/src/api-client.ts +69 -0
  14. package/scaffold/mcp-pm/src/index.ts +660 -0
  15. package/scaffold/mcp-pm/tsconfig.json +14 -0
  16. package/scaffold/pm-api/package.json +21 -0
  17. package/scaffold/pm-api/sql/001-memo-v2.sql +49 -0
  18. package/scaffold/pm-api/sql/002-notifications.sql +18 -0
  19. package/scaffold/pm-api/sql/003-content.sql +66 -0
  20. package/scaffold/pm-api/sql/004-agent-events.sql +21 -0
  21. package/scaffold/pm-api/sql/005-epic-sprint-decoupling.sql +6 -0
  22. package/scaffold/pm-api/sql/schema-core.sql +331 -0
  23. package/scaffold/pm-api/sql/schema-docs.sql +25 -0
  24. package/scaffold/pm-api/sql/schema-meetings.sql +17 -0
  25. package/scaffold/pm-api/sql/schema-rewards.sql +16 -0
  26. package/scaffold/pm-api/src/auth.ts +28 -0
  27. package/scaffold/pm-api/src/blockchain/adapter.ts +20 -0
  28. package/scaffold/pm-api/src/blockchain/tron.ts +62 -0
  29. package/scaffold/pm-api/src/db/adapter.ts +36 -0
  30. package/scaffold/pm-api/src/db/turso.ts +147 -0
  31. package/scaffold/pm-api/src/index.ts +114 -0
  32. package/scaffold/pm-api/src/mcp-tools/dashboard.ts +40 -0
  33. package/scaffold/pm-api/src/mcp-tools/epic.ts +67 -0
  34. package/scaffold/pm-api/src/mcp-tools/event.ts +89 -0
  35. package/scaffold/pm-api/src/mcp-tools/index.ts +11 -0
  36. package/scaffold/pm-api/src/mcp-tools/initiative.ts +51 -0
  37. package/scaffold/pm-api/src/mcp-tools/memo.ts +164 -0
  38. package/scaffold/pm-api/src/mcp-tools/notification.ts +37 -0
  39. package/scaffold/pm-api/src/mcp-tools/retro.ts +183 -0
  40. package/scaffold/pm-api/src/mcp-tools/sprint.ts +204 -0
  41. package/scaffold/pm-api/src/mcp-tools/standup.ts +136 -0
  42. package/scaffold/pm-api/src/mcp-tools/story.ts +230 -0
  43. package/scaffold/pm-api/src/mcp-tools/task.ts +187 -0
  44. package/scaffold/pm-api/src/mcp-tools/utils.ts +83 -0
  45. package/scaffold/pm-api/src/mcp.ts +871 -0
  46. package/scaffold/pm-api/src/nudge.ts +283 -0
  47. package/scaffold/pm-api/src/routes/auth.ts +32 -0
  48. package/scaffold/pm-api/src/routes/v2-activity.ts +27 -0
  49. package/scaffold/pm-api/src/routes/v2-admin.ts +165 -0
  50. package/scaffold/pm-api/src/routes/v2-dashboard.ts +189 -0
  51. package/scaffold/pm-api/src/routes/v2-docs.ts +34 -0
  52. package/scaffold/pm-api/src/routes/v2-initiatives.ts +118 -0
  53. package/scaffold/pm-api/src/routes/v2-kickoff.ts +265 -0
  54. package/scaffold/pm-api/src/routes/v2-meetings.ts +324 -0
  55. package/scaffold/pm-api/src/routes/v2-memos.ts +257 -0
  56. package/scaffold/pm-api/src/routes/v2-nav.ts +260 -0
  57. package/scaffold/pm-api/src/routes/v2-notifications.ts +79 -0
  58. package/scaffold/pm-api/src/routes/v2-page-content.ts +35 -0
  59. package/scaffold/pm-api/src/routes/v2-pm.ts +380 -0
  60. package/scaffold/pm-api/src/routes/v2-policy.ts +58 -0
  61. package/scaffold/pm-api/src/routes/v2-retro.ts +221 -0
  62. package/scaffold/pm-api/src/routes/v2-rewards.ts +132 -0
  63. package/scaffold/pm-api/src/routes/v2-scenarios.ts +48 -0
  64. package/scaffold/pm-api/src/routes/v2-search.ts +32 -0
  65. package/scaffold/pm-api/src/routes/v2-standup.ts +127 -0
  66. package/scaffold/pm-api/src/routes/v2-user.ts +38 -0
  67. package/scaffold/pm-api/src/types.ts +11 -0
  68. package/scaffold/pm-api/src/utils/activity.ts +22 -0
  69. package/scaffold/pm-api/src/utils/admin.ts +9 -0
  70. package/scaffold/pm-api/src/utils/agent-notify.ts +62 -0
  71. package/scaffold/pm-api/src/utils/assignee.ts +69 -0
  72. package/scaffold/pm-api/src/utils/db.ts +45 -0
  73. package/scaffold/pm-api/src/utils/initiative.ts +23 -0
  74. package/scaffold/pm-api/src/utils/retro-link.ts +32 -0
  75. package/scaffold/pm-api/src/utils/sprint-lifecycle.ts +96 -0
  76. package/scaffold/pm-api/tsconfig.json +15 -0
  77. package/scaffold/pm-api/wrangler.toml.hbs +11 -0
  78. package/scaffold/spec-site/package-lock.json +892 -0
  79. package/scaffold/spec-site/package.json +15 -1
  80. package/scaffold/spec-site/src/api/types.ts +6 -0
  81. package/scaffold/spec-site/src/components/AppHeader.vue +429 -55
  82. package/scaffold/spec-site/src/components/AuthGate.vue +117 -0
  83. package/scaffold/spec-site/src/components/BurndownChart.vue +78 -0
  84. package/scaffold/spec-site/src/components/DocComments.vue +137 -0
  85. package/scaffold/spec-site/src/components/DocEditor.vue +118 -0
  86. package/scaffold/spec-site/src/components/DocExportBar.vue +110 -0
  87. package/scaffold/spec-site/src/components/DocsSidebar.vue +309 -0
  88. package/scaffold/spec-site/src/components/EmptyState.vue +30 -0
  89. package/scaffold/spec-site/src/components/ErrorBanner.vue +38 -0
  90. package/scaffold/spec-site/src/components/Icon.vue +58 -0
  91. package/scaffold/spec-site/src/components/MemberSelect.vue +48 -0
  92. package/scaffold/spec-site/src/components/MemoChecklist.vue +88 -0
  93. package/scaffold/spec-site/src/components/MemoGraph.vue +75 -0
  94. package/scaffold/spec-site/src/components/MemoItem.vue +353 -0
  95. package/scaffold/spec-site/src/components/MemoRelations.vue +101 -0
  96. package/scaffold/spec-site/src/components/MemoTimeline.vue +53 -0
  97. package/scaffold/spec-site/src/components/MentionInput.vue +174 -0
  98. package/scaffold/spec-site/src/components/NotificationDropdown.vue +116 -0
  99. package/scaffold/spec-site/src/components/PriorityBadge.vue +23 -0
  100. package/scaffold/spec-site/src/components/SearchModal.vue +102 -0
  101. package/scaffold/spec-site/src/components/SlashCommand.ts +123 -0
  102. package/scaffold/spec-site/src/components/StateDisplay.vue +54 -0
  103. package/scaffold/spec-site/src/components/TreeNode.vue +82 -0
  104. package/scaffold/spec-site/src/components/UserAvatar.vue +24 -0
  105. package/scaffold/spec-site/src/components/VelocityChart.vue +77 -0
  106. package/scaffold/spec-site/src/composables/navTypes.ts +3 -0
  107. package/scaffold/spec-site/src/composables/pmTypes.ts +15 -2
  108. package/scaffold/spec-site/src/composables/useBottomSheet.ts +103 -0
  109. package/scaffold/spec-site/src/composables/useDashboard.ts +221 -0
  110. package/scaffold/spec-site/src/composables/useMediaQuery.ts +28 -0
  111. package/scaffold/spec-site/src/composables/useMemo.ts +39 -0
  112. package/scaffold/spec-site/src/composables/useNotification.ts +200 -0
  113. package/scaffold/spec-site/src/composables/usePmStore.ts +48 -1
  114. package/scaffold/spec-site/src/composables/useRetro.ts +6 -0
  115. package/scaffold/spec-site/src/composables/useStandup.ts +201 -0
  116. package/scaffold/spec-site/src/composables/useTheme.ts +37 -0
  117. package/scaffold/spec-site/src/composables/useTurso.ts +17 -0
  118. package/scaffold/spec-site/src/composables/useUser.ts +19 -1
  119. package/scaffold/spec-site/src/composables/useViewport.ts +26 -0
  120. package/scaffold/spec-site/src/features.ts +108 -0
  121. package/scaffold/spec-site/src/mockup/ComponentPalette.vue +61 -0
  122. package/scaffold/spec-site/src/mockup/MockupCanvas.vue +459 -0
  123. package/scaffold/spec-site/src/mockup/PropertyPanel.vue +217 -0
  124. package/scaffold/spec-site/src/mockup/componentCatalog.ts +68 -0
  125. package/scaffold/spec-site/src/mockup/useScenarios.ts +67 -0
  126. package/scaffold/spec-site/src/pages/AdminPage.vue +299 -0
  127. package/scaffold/spec-site/src/pages/DashboardPage.vue +650 -0
  128. package/scaffold/spec-site/src/pages/DocsEditor.vue +119 -0
  129. package/scaffold/spec-site/src/pages/DocsHub.vue +157 -0
  130. package/scaffold/spec-site/src/pages/DocsPage.vue +444 -0
  131. package/scaffold/spec-site/src/pages/InboxPage.vue +156 -0
  132. package/scaffold/spec-site/src/pages/MeetingsPage.vue +294 -0
  133. package/scaffold/spec-site/src/pages/MemosPage.vue +857 -0
  134. package/scaffold/spec-site/src/pages/MockupEditorPage.vue +611 -0
  135. package/scaffold/spec-site/src/pages/MockupListPage.vue +121 -0
  136. package/scaffold/spec-site/src/pages/MockupViewerPage.vue +199 -0
  137. package/scaffold/spec-site/src/pages/MyPage.vue +343 -0
  138. package/scaffold/spec-site/src/pages/NotificationSettingsPage.vue +59 -0
  139. package/scaffold/spec-site/src/pages/RewardsPage.vue +266 -0
  140. package/scaffold/spec-site/src/pages/SprintAdmin.vue +521 -0
  141. package/scaffold/spec-site/src/pages/SprintTimeline.vue +159 -0
  142. package/scaffold/spec-site/src/pages/board/BoardAdmin.vue +422 -0
  143. package/scaffold/spec-site/src/pages/board/BoardEpicSection.vue +54 -0
  144. package/scaffold/spec-site/src/pages/board/BoardPage.vue +884 -0
  145. package/scaffold/spec-site/src/pages/board/BoardStoryCard.vue +67 -0
  146. package/scaffold/spec-site/src/pages/board/BoardTaskItem.vue +52 -0
  147. package/scaffold/spec-site/src/pages/board/KanbanBoard.vue +93 -0
  148. package/scaffold/spec-site/src/pages/board/MyTasksPage.vue +202 -0
  149. package/scaffold/spec-site/src/pages/board/SprintClose.vue +167 -0
  150. package/scaffold/spec-site/src/pages/board/SprintColumn.vue +49 -0
  151. package/scaffold/spec-site/src/pages/board/SprintKickoff.vue +389 -0
  152. package/scaffold/spec-site/src/pages/board/StatusBadge.vue +52 -0
  153. package/scaffold/spec-site/src/pages/board/StoryDetailPanel.vue +495 -0
  154. package/scaffold/spec-site/src/pages/board/TaskCard.vue +42 -0
  155. package/scaffold/spec-site/src/pages/retro/RetroCard.vue +36 -2
  156. package/scaffold/spec-site/src/pages/retro/RetroHeader.vue +82 -66
  157. package/scaffold/spec-site/src/pages/retro/RetroPage.vue +47 -18
  158. package/scaffold/spec-site/src/pages/standup/StandupEntryCard.vue +551 -0
  159. package/scaffold/spec-site/src/pages/standup/StandupForm.vue +68 -0
  160. package/scaffold/spec-site/src/pages/standup/StandupList.vue +71 -0
  161. package/scaffold/spec-site/src/pages/standup/StandupPage.vue +225 -0
  162. package/scaffold/spec-site/src/router.ts +141 -0
  163. package/scaffold/spec-site/src/styles/buttons.css +124 -0
  164. package/scaffold/spec-site/src/utils/parseMentions.ts +56 -0
  165. package/scaffold/spec-site/src/utils/timezone.ts +18 -0
@@ -1,23 +1,40 @@
1
1
  <script setup lang="ts">
2
- import { ref } from 'vue'
2
+ import { ref, computed } from 'vue'
3
3
  import type { RetroSession, RetroPhase } from '@/composables/useRetro'
4
4
  import { VOTES_PER_PERSON } from '@/composables/useRetro'
5
+
6
+ const AUTHOR_COLORS = ['#3b82f6', '#10b981', '#f59e0b', '#ef4444', '#8b5cf6', '#ec4899', '#14b8a6', '#f97316']
7
+
5
8
  const props = defineProps<{
6
9
  session: RetroSession | null
7
10
  sprintId: string
8
- currentUser: string | null
11
+ currentUser: string
9
12
  votesRemaining: number
10
13
  teamMembers: string[]
14
+ participants: string[]
15
+ itemCount?: number
11
16
  }>()
12
17
 
13
18
  const emit = defineEmits<{
14
19
  (e: 'phase-change', phase: RetroPhase): void
15
- (e: 'select-user', name: string): void
16
20
  (e: 'reset'): void
17
21
  (e: 'export'): void
18
22
  }>()
19
23
 
20
- const userOpen = ref(false)
24
+ function authorColor(name: string): string {
25
+ let hash = 0
26
+ for (let i = 0; i < name.length; i++) hash = name.charCodeAt(i) + ((hash << 5) - hash)
27
+ return AUTHOR_COLORS[Math.abs(hash) % AUTHOR_COLORS.length]
28
+ }
29
+
30
+ const participantList = computed(() =>
31
+ props.participants.map(name => ({
32
+ name,
33
+ initial: name.charAt(0),
34
+ color: authorColor(name),
35
+ isMe: name === props.currentUser,
36
+ }))
37
+ )
21
38
 
22
39
  const PHASE_META: Record<RetroPhase, { label: string; next: string }> = {
23
40
  write: { label: 'Writing', next: 'Start Voting' },
@@ -36,6 +53,11 @@ function prevPhase() {
36
53
 
37
54
  function nextPhase() {
38
55
  if (!props.session) return
56
+ // write -> vote: require at least 1 card
57
+ if (props.session.phase === 'write' && (props.itemCount ?? 0) === 0) {
58
+ alert('Add at least one card before starting the vote.')
59
+ return
60
+ }
39
61
  const idx = PHASE_ORDER.indexOf(props.session.phase)
40
62
  if (idx < PHASE_ORDER.length - 1) emit('phase-change', PHASE_ORDER[idx + 1])
41
63
  }
@@ -44,11 +66,6 @@ function phase(): RetroPhase {
44
66
  return props.session?.phase ?? 'write'
45
67
  }
46
68
 
47
- function selectMember(name: string) {
48
- emit('select-user', name)
49
- userOpen.value = false
50
- }
51
-
52
69
  const menuOpen = ref(false)
53
70
 
54
71
  function handleReset() {
@@ -76,30 +93,33 @@ function handleExport() {
76
93
  </span>
77
94
  </div>
78
95
  <div class="rh-right">
79
- <!-- User selector -->
80
- <div class="rh-user-wrap">
81
- <button class="rh-user-btn" @click.stop="userOpen = !userOpen">
82
- {{ currentUser ?? 'Select name' }}
83
- <span class="rh-chevron">&#9662;</span>
84
- </button>
85
- <div v-if="userOpen" class="rh-user-menu">
86
- <div
87
- v-for="m in teamMembers"
88
- :key="m"
89
- class="rh-user-item"
90
- :class="{ active: m === currentUser }"
91
- @click="selectMember(m)"
92
- >
93
- {{ m }}
94
- </div>
96
+ <!-- Participants -->
97
+ <div class="rh-participants">
98
+ <div
99
+ v-for="p in participantList"
100
+ :key="p.name"
101
+ class="rh-avatar"
102
+ :class="{ 'rh-avatar--me': p.isMe }"
103
+ :style="{ background: p.color }"
104
+ :title="p.name + (p.isMe ? ' (me)' : '')"
105
+ >
106
+ {{ p.initial }}
95
107
  </div>
108
+ <span v-if="participantList.length === 0" class="rh-no-participants">No participants yet</span>
109
+ <span v-else class="rh-participant-count">{{ participantList.length }} joined</span>
110
+ </div>
111
+
112
+ <!-- Current user badge -->
113
+ <div v-if="currentUser" class="rh-me-badge">
114
+ <span class="rh-me-dot" :style="{ background: authorColor(currentUser) }" />
115
+ {{ currentUser }}
96
116
  </div>
97
117
 
98
118
  <!-- Phase controls -->
99
119
  <button v-if="phase() !== 'write'" class="rh-prev" @click="prevPhase">
100
120
  &larr; Prev
101
121
  </button>
102
- <button v-if="phase() !== 'done'" class="rh-next" @click="nextPhase">
122
+ <button v-if="phase() !== 'done'" class="rh-next" :disabled="phase() === 'write' && (itemCount ?? 0) === 0" @click="nextPhase">
103
123
  {{ PHASE_META[phase()].next }} &rarr;
104
124
  </button>
105
125
 
@@ -159,54 +179,51 @@ function handleExport() {
159
179
  gap: 8px;
160
180
  }
161
181
 
162
- /* -- User dropdown -- */
163
- .rh-user-wrap { position: relative; }
164
-
165
- .rh-user-btn {
182
+ /* -- Participants -- */
183
+ .rh-participants {
166
184
  display: flex;
167
185
  align-items: center;
168
186
  gap: 4px;
169
- padding: 6px 12px;
170
- border: 1px solid var(--border);
171
- border-radius: 6px;
172
- background: #fff;
173
- font-size: 13px;
174
- font-weight: 500;
175
- font-family: var(--font-sans);
176
- cursor: pointer;
177
- color: var(--text-primary);
178
- transition: all 0.15s;
179
187
  }
180
- .rh-user-btn:hover { background: var(--bg); }
181
188
 
182
- .rh-chevron {
183
- font-size: 10px;
184
- color: var(--text-muted);
189
+ .rh-avatar {
190
+ width: 26px;
191
+ height: 26px;
192
+ border-radius: 50%;
193
+ display: flex;
194
+ align-items: center;
195
+ justify-content: center;
196
+ color: #fff;
197
+ font-size: 11px;
198
+ font-weight: 700;
199
+ flex-shrink: 0;
200
+ border: 2px solid transparent;
201
+ transition: transform 0.15s;
185
202
  }
203
+ .rh-avatar:hover { transform: scale(1.15); }
204
+ .rh-avatar--me { border-color: var(--primary); box-shadow: 0 0 0 1px #fff; }
186
205
 
187
- .rh-user-menu {
188
- position: absolute;
189
- top: calc(100% + 4px);
190
- right: 0;
191
- min-width: 120px;
192
- background: #fff;
193
- border: 1px solid var(--border);
194
- border-radius: 8px;
195
- box-shadow: var(--shadow-md);
196
- padding: 4px;
197
- z-index: 100;
198
- }
206
+ .rh-no-participants { font-size: 12px; color: var(--text-muted); }
207
+ .rh-participant-count { font-size: 11px; color: var(--text-muted); margin-left: 2px; }
199
208
 
200
- .rh-user-item {
201
- padding: 6px 12px;
202
- font-size: 13px;
209
+ .rh-me-badge {
210
+ display: flex;
211
+ align-items: center;
212
+ gap: 6px;
213
+ padding: 4px 10px;
214
+ background: var(--bg);
215
+ border: 1px solid var(--border);
203
216
  border-radius: 6px;
204
- cursor: pointer;
205
- color: var(--text-secondary);
206
- transition: all 0.1s;
217
+ font-size: 12px;
218
+ font-weight: 600;
219
+ color: var(--text-primary);
220
+ }
221
+ .rh-me-dot {
222
+ width: 8px;
223
+ height: 8px;
224
+ border-radius: 50%;
225
+ flex-shrink: 0;
207
226
  }
208
- .rh-user-item:hover { background: var(--bg); color: var(--text-primary); }
209
- .rh-user-item.active { color: var(--primary); font-weight: 600; }
210
227
 
211
228
  /* -- Phase buttons -- */
212
229
  .rh-prev {
@@ -217,7 +234,6 @@ function handleExport() {
217
234
  border-radius: 6px;
218
235
  font-size: 13px;
219
236
  font-weight: 500;
220
- font-family: var(--font-sans);
221
237
  cursor: pointer;
222
238
  transition: all 0.15s;
223
239
  }
@@ -231,11 +247,11 @@ function handleExport() {
231
247
  border-radius: 6px;
232
248
  font-size: 13px;
233
249
  font-weight: 600;
234
- font-family: var(--font-sans);
235
250
  cursor: pointer;
236
251
  transition: opacity 0.15s;
237
252
  }
238
253
  .rh-next:hover { opacity: 0.9; }
254
+ .rh-next:disabled { opacity: 0.5; cursor: not-allowed; }
239
255
 
240
256
  /* -- More menu -- */
241
257
  .rh-menu-wrap { position: relative; }
@@ -1,26 +1,32 @@
1
1
  <script setup lang="ts">
2
- import { onMounted, watch } from 'vue'
3
- import { useRoute } from 'vue-router'
2
+ import { onMounted, computed } from 'vue'
3
+ import { useRoute, useRouter } from 'vue-router'
4
4
  import { useUser } from '@/composables/useUser'
5
5
  import { useRetro } from '@/composables/useRetro'
6
6
  import { getActiveSprint } from '@/composables/useNavStore'
7
+ import { apiPost } from '@/api/client'
7
8
  import RetroHeader from './RetroHeader.vue'
8
9
  import RetroBoard from './RetroBoard.vue'
9
10
  import RetroActions from './RetroActions.vue'
10
11
 
11
12
  const route = useRoute()
13
+ const router = useRouter()
12
14
  const sprintId = (route.params.sprint as string) || getActiveSprint().id
13
15
 
14
- const { currentUser, setUser, TEAM_MEMBERS } = useUser()
16
+ async function completeAndKickoff() {
17
+ await apiPost(`/api/v2/retro/${sprintId}/complete`, {})
18
+ router.push('/kickoff/new')
19
+ }
20
+
21
+ const { currentUser, dynamicMembers, loadMembers } = useUser()
15
22
  const retro = useRetro(sprintId)
16
23
 
24
+ const userName = computed(() => currentUser.value ?? localStorage.getItem('retro-user-name') ?? '')
25
+
17
26
  onMounted(async () => {
27
+ loadMembers()
18
28
  await retro.loadOrCreateSession()
19
- retro.startPolling(currentUser.value ?? '')
20
- })
21
-
22
- watch(currentUser, (nextUser) => {
23
- retro.startPolling(nextUser ?? '')
29
+ retro.startPolling(userName.value)
24
30
  })
25
31
 
26
32
  function handleExport() {
@@ -37,11 +43,12 @@ function handleExport() {
37
43
  <RetroHeader
38
44
  :session="retro.session.value"
39
45
  :sprint-id="sprintId"
40
- :current-user="currentUser"
46
+ :current-user="userName"
41
47
  :votes-remaining="retro.votesRemaining.value"
42
- :team-members="[...TEAM_MEMBERS]"
48
+ :team-members="dynamicMembers"
49
+ :participants="retro.participants.value"
50
+ :item-count="retro.items.value.length"
43
51
  @phase-change="retro.setPhase"
44
- @select-user="setUser"
45
52
  @reset="retro.resetSession"
46
53
  @export="handleExport"
47
54
  />
@@ -64,21 +71,28 @@ function handleExport() {
64
71
  :problem-items="retro.problemItems.value"
65
72
  :try-items="retro.tryItems.value"
66
73
  :phase="retro.session.value.phase"
67
- :current-user="currentUser ?? ''"
74
+ :current-user="userName"
68
75
  :votes-remaining="retro.votesRemaining.value"
69
76
  @add-item="retro.addItem"
70
- @delete-item="(id) => retro.deleteItem(id, currentUser ?? '')"
71
- @toggle-vote="(id, hasVoted) => retro.toggleVote(id, currentUser ?? '', hasVoted)"
77
+ @delete-item="(id) => retro.deleteItem(id, userName)"
78
+ @toggle-vote="(id, hasVoted) => retro.toggleVote(id, userName, hasVoted)"
72
79
  />
73
80
 
74
81
  <div v-if="retro.session.value?.phase === 'done'" class="retro-done">
75
- <div class="done-banner">Retro completed</div>
82
+ <div class="done-banner">
83
+ Retrospective completed
84
+ <div class="done-actions">
85
+ <button class="btn btn--primary" @click="completeAndKickoff">
86
+ Next Sprint Kickoff &rarr;
87
+ </button>
88
+ </div>
89
+ </div>
76
90
  <RetroBoard
77
91
  :keep-items="retro.keepItems.value"
78
92
  :problem-items="retro.problemItems.value"
79
93
  :try-items="retro.tryItems.value"
80
94
  phase="discuss"
81
- :current-user="currentUser ?? ''"
95
+ :current-user="userName"
82
96
  :votes-remaining="0"
83
97
  @add-item="() => {}"
84
98
  @delete-item="() => {}"
@@ -92,7 +106,7 @@ function handleExport() {
92
106
  retro.session.value?.phase === 'done'
93
107
  "
94
108
  :actions="retro.actions.value"
95
- :team-members="[...TEAM_MEMBERS]"
109
+ :team-members="dynamicMembers"
96
110
  :readonly="retro.session.value?.phase === 'done'"
97
111
  @add-action="retro.addAction"
98
112
  @toggle-status="retro.toggleActionStatus"
@@ -155,7 +169,6 @@ function handleExport() {
155
169
  border-radius: 6px;
156
170
  font-size: 13px;
157
171
  font-weight: 600;
158
- font-family: var(--font-sans);
159
172
  cursor: pointer;
160
173
  }
161
174
 
@@ -175,4 +188,20 @@ function handleExport() {
175
188
  font-size: 14px;
176
189
  border-bottom: 1px solid var(--green-border);
177
190
  }
191
+ .done-actions {
192
+ margin-top: 8px;
193
+ }
194
+ .btn {
195
+ padding: 8px 16px;
196
+ border: none;
197
+ border-radius: 6px;
198
+ font-size: 13px;
199
+ font-weight: 600;
200
+ cursor: pointer;
201
+ }
202
+ .btn--primary {
203
+ background: var(--primary);
204
+ color: #fff;
205
+ }
206
+ .btn--primary:hover { opacity: 0.9; }
178
207
  </style>