popilot 0.6.0 → 0.7.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.
- package/bin/cli.mjs +204 -2
- package/lib/doctor.mjs +38 -1
- package/lib/hydrate.mjs +15 -0
- package/lib/scaffold.mjs +5 -0
- package/lib/setup-wizard.mjs +35 -2
- package/package.json +1 -1
- package/scaffold/.context/project.yaml.example +19 -0
- package/scaffold/mcp-pm/package.json +19 -0
- package/scaffold/mcp-pm/src/api-client.ts +69 -0
- package/scaffold/mcp-pm/src/index.ts +660 -0
- package/scaffold/mcp-pm/tsconfig.json +14 -0
- package/scaffold/pm-api/package.json +21 -0
- package/scaffold/pm-api/sql/schema-core.sql +331 -0
- package/scaffold/pm-api/sql/schema-docs.sql +25 -0
- package/scaffold/pm-api/sql/schema-meetings.sql +17 -0
- package/scaffold/pm-api/sql/schema-rewards.sql +16 -0
- package/scaffold/pm-api/src/auth.ts +28 -0
- package/scaffold/pm-api/src/blockchain/adapter.ts +20 -0
- package/scaffold/pm-api/src/blockchain/tron.ts +62 -0
- package/scaffold/pm-api/src/db/adapter.ts +36 -0
- package/scaffold/pm-api/src/db/turso.ts +147 -0
- package/scaffold/pm-api/src/index.ts +114 -0
- package/scaffold/pm-api/src/mcp-tools/dashboard.ts +40 -0
- package/scaffold/pm-api/src/mcp-tools/epic.ts +67 -0
- package/scaffold/pm-api/src/mcp-tools/event.ts +89 -0
- package/scaffold/pm-api/src/mcp-tools/index.ts +11 -0
- package/scaffold/pm-api/src/mcp-tools/initiative.ts +51 -0
- package/scaffold/pm-api/src/mcp-tools/memo.ts +164 -0
- package/scaffold/pm-api/src/mcp-tools/notification.ts +37 -0
- package/scaffold/pm-api/src/mcp-tools/retro.ts +183 -0
- package/scaffold/pm-api/src/mcp-tools/sprint.ts +204 -0
- package/scaffold/pm-api/src/mcp-tools/standup.ts +136 -0
- package/scaffold/pm-api/src/mcp-tools/story.ts +230 -0
- package/scaffold/pm-api/src/mcp-tools/task.ts +187 -0
- package/scaffold/pm-api/src/mcp-tools/utils.ts +83 -0
- package/scaffold/pm-api/src/mcp.ts +871 -0
- package/scaffold/pm-api/src/nudge.ts +283 -0
- package/scaffold/pm-api/src/routes/auth.ts +32 -0
- package/scaffold/pm-api/src/routes/v2-activity.ts +27 -0
- package/scaffold/pm-api/src/routes/v2-admin.ts +165 -0
- package/scaffold/pm-api/src/routes/v2-dashboard.ts +189 -0
- package/scaffold/pm-api/src/routes/v2-docs.ts +34 -0
- package/scaffold/pm-api/src/routes/v2-initiatives.ts +118 -0
- package/scaffold/pm-api/src/routes/v2-kickoff.ts +265 -0
- package/scaffold/pm-api/src/routes/v2-meetings.ts +324 -0
- package/scaffold/pm-api/src/routes/v2-memos.ts +257 -0
- package/scaffold/pm-api/src/routes/v2-nav.ts +260 -0
- package/scaffold/pm-api/src/routes/v2-notifications.ts +79 -0
- package/scaffold/pm-api/src/routes/v2-page-content.ts +35 -0
- package/scaffold/pm-api/src/routes/v2-pm.ts +380 -0
- package/scaffold/pm-api/src/routes/v2-policy.ts +58 -0
- package/scaffold/pm-api/src/routes/v2-retro.ts +221 -0
- package/scaffold/pm-api/src/routes/v2-rewards.ts +132 -0
- package/scaffold/pm-api/src/routes/v2-scenarios.ts +48 -0
- package/scaffold/pm-api/src/routes/v2-search.ts +32 -0
- package/scaffold/pm-api/src/routes/v2-standup.ts +127 -0
- package/scaffold/pm-api/src/routes/v2-user.ts +38 -0
- package/scaffold/pm-api/src/types.ts +11 -0
- package/scaffold/pm-api/src/utils/activity.ts +22 -0
- package/scaffold/pm-api/src/utils/admin.ts +9 -0
- package/scaffold/pm-api/src/utils/agent-notify.ts +62 -0
- package/scaffold/pm-api/src/utils/assignee.ts +69 -0
- package/scaffold/pm-api/src/utils/db.ts +45 -0
- package/scaffold/pm-api/src/utils/initiative.ts +23 -0
- package/scaffold/pm-api/src/utils/sprint-lifecycle.ts +96 -0
- package/scaffold/pm-api/tsconfig.json +15 -0
- package/scaffold/pm-api/wrangler.toml.hbs +11 -0
- package/scaffold/spec-site/package-lock.json +40 -0
- package/scaffold/spec-site/package.json +4 -1
- package/scaffold/spec-site/src/api/types.ts +6 -0
- package/scaffold/spec-site/src/components/AppHeader.vue +429 -55
- package/scaffold/spec-site/src/components/MemberSelect.vue +48 -0
- package/scaffold/spec-site/src/components/NotificationDropdown.vue +116 -0
- package/scaffold/spec-site/src/components/SearchModal.vue +102 -0
- package/scaffold/spec-site/src/components/VelocityChart.vue +77 -0
- package/scaffold/spec-site/src/composables/pmTypes.ts +15 -2
- package/scaffold/spec-site/src/composables/useDashboard.ts +221 -0
- package/scaffold/spec-site/src/composables/useMediaQuery.ts +28 -0
- package/scaffold/spec-site/src/composables/useNotification.ts +200 -0
- package/scaffold/spec-site/src/composables/usePmStore.ts +48 -1
- package/scaffold/spec-site/src/composables/useRetro.ts +6 -0
- package/scaffold/spec-site/src/composables/useStandup.ts +201 -0
- package/scaffold/spec-site/src/composables/useTheme.ts +37 -0
- package/scaffold/spec-site/src/composables/useUser.ts +19 -1
- package/scaffold/spec-site/src/features.ts +108 -0
- package/scaffold/spec-site/src/pages/AdminPage.vue +299 -0
- package/scaffold/spec-site/src/pages/DashboardPage.vue +650 -0
- package/scaffold/spec-site/src/pages/DocsHub.vue +157 -0
- package/scaffold/spec-site/src/pages/InboxPage.vue +156 -0
- package/scaffold/spec-site/src/pages/MeetingsPage.vue +294 -0
- package/scaffold/spec-site/src/pages/MyPage.vue +343 -0
- package/scaffold/spec-site/src/pages/RewardsPage.vue +266 -0
- package/scaffold/spec-site/src/pages/board/BoardAdmin.vue +422 -0
- package/scaffold/spec-site/src/pages/board/BoardEpicSection.vue +54 -0
- package/scaffold/spec-site/src/pages/board/BoardPage.vue +884 -0
- package/scaffold/spec-site/src/pages/board/BoardStoryCard.vue +67 -0
- package/scaffold/spec-site/src/pages/board/BoardTaskItem.vue +52 -0
- package/scaffold/spec-site/src/pages/board/MyTasksPage.vue +202 -0
- package/scaffold/spec-site/src/pages/board/SprintClose.vue +167 -0
- package/scaffold/spec-site/src/pages/board/SprintColumn.vue +49 -0
- package/scaffold/spec-site/src/pages/board/SprintKickoff.vue +389 -0
- package/scaffold/spec-site/src/pages/board/StatusBadge.vue +52 -0
- package/scaffold/spec-site/src/pages/board/StoryDetailPanel.vue +495 -0
- package/scaffold/spec-site/src/pages/board/TaskCard.vue +42 -0
- package/scaffold/spec-site/src/pages/retro/RetroCard.vue +36 -2
- package/scaffold/spec-site/src/pages/retro/RetroHeader.vue +82 -66
- package/scaffold/spec-site/src/pages/retro/RetroPage.vue +47 -18
- package/scaffold/spec-site/src/pages/standup/StandupEntryCard.vue +551 -0
- package/scaffold/spec-site/src/pages/standup/StandupForm.vue +68 -0
- package/scaffold/spec-site/src/pages/standup/StandupList.vue +71 -0
- package/scaffold/spec-site/src/pages/standup/StandupPage.vue +225 -0
- package/scaffold/spec-site/src/router.ts +141 -0
|
@@ -0,0 +1,96 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Sprint Lifecycle — pure domain logic
|
|
3
|
+
* No DB dependency. Fully testable.
|
|
4
|
+
*/
|
|
5
|
+
|
|
6
|
+
export interface StoryRow {
|
|
7
|
+
id: number
|
|
8
|
+
title: string
|
|
9
|
+
sprint: string | null
|
|
10
|
+
status: string
|
|
11
|
+
story_points: number | null
|
|
12
|
+
assignee: string | null
|
|
13
|
+
}
|
|
14
|
+
|
|
15
|
+
export interface SprintStatus {
|
|
16
|
+
id: string
|
|
17
|
+
status: 'planning' | 'active' | 'closed'
|
|
18
|
+
}
|
|
19
|
+
|
|
20
|
+
export interface VelocityRecord {
|
|
21
|
+
sprintId: string
|
|
22
|
+
assignee: string
|
|
23
|
+
doneSP: number
|
|
24
|
+
totalSP: number
|
|
25
|
+
}
|
|
26
|
+
|
|
27
|
+
export interface CloseSummary {
|
|
28
|
+
sprintId: string
|
|
29
|
+
completedCount: number
|
|
30
|
+
incompleteCount: number
|
|
31
|
+
totalStories: number
|
|
32
|
+
doneSP: number
|
|
33
|
+
totalSP: number
|
|
34
|
+
completionRate: number
|
|
35
|
+
}
|
|
36
|
+
|
|
37
|
+
/** Check whether the sprint can be closed */
|
|
38
|
+
export function canClose(sprint: SprintStatus): { ok: boolean; error?: string } {
|
|
39
|
+
if (sprint.status !== 'active') {
|
|
40
|
+
return { ok: false, error: `Can only close sprints in active state (current: ${sprint.status})` }
|
|
41
|
+
}
|
|
42
|
+
return { ok: true }
|
|
43
|
+
}
|
|
44
|
+
|
|
45
|
+
/** Filter incomplete stories */
|
|
46
|
+
export function getIncompleteStories(stories: StoryRow[]): StoryRow[] {
|
|
47
|
+
return stories.filter(s => s.status !== 'done')
|
|
48
|
+
}
|
|
49
|
+
|
|
50
|
+
/** Filter completed stories */
|
|
51
|
+
export function getCompletedStories(stories: StoryRow[]): StoryRow[] {
|
|
52
|
+
return stories.filter(s => s.status === 'done')
|
|
53
|
+
}
|
|
54
|
+
|
|
55
|
+
/** Move incomplete stories to backlog (pure function — returns new array) */
|
|
56
|
+
export function moveToBacklog(stories: StoryRow[]): StoryRow[] {
|
|
57
|
+
return stories.map(s => ({ ...s, sprint: null }))
|
|
58
|
+
}
|
|
59
|
+
|
|
60
|
+
/** Aggregate completed SP per team member */
|
|
61
|
+
export function aggregateVelocity(sprintId: string, stories: StoryRow[]): VelocityRecord[] {
|
|
62
|
+
const map = new Map<string, { done: number; total: number }>()
|
|
63
|
+
|
|
64
|
+
for (const s of stories) {
|
|
65
|
+
const assignee = s.assignee ?? 'Unassigned'
|
|
66
|
+
if (!map.has(assignee)) map.set(assignee, { done: 0, total: 0 })
|
|
67
|
+
const entry = map.get(assignee)!
|
|
68
|
+
entry.total += s.story_points ?? 0
|
|
69
|
+
if (s.status === 'done') entry.done += s.story_points ?? 0
|
|
70
|
+
}
|
|
71
|
+
|
|
72
|
+
return [...map.entries()].map(([assignee, { done, total }]) => ({
|
|
73
|
+
sprintId,
|
|
74
|
+
assignee,
|
|
75
|
+
doneSP: done,
|
|
76
|
+
totalSP: total,
|
|
77
|
+
}))
|
|
78
|
+
}
|
|
79
|
+
|
|
80
|
+
/** Generate close summary */
|
|
81
|
+
export function generateCloseSummary(sprintId: string, stories: StoryRow[]): CloseSummary {
|
|
82
|
+
const completed = getCompletedStories(stories)
|
|
83
|
+
const incomplete = getIncompleteStories(stories)
|
|
84
|
+
const totalDoneSP = completed.reduce((sum, s) => sum + (s.story_points ?? 0), 0)
|
|
85
|
+
const totalSP = stories.reduce((sum, s) => sum + (s.story_points ?? 0), 0)
|
|
86
|
+
|
|
87
|
+
return {
|
|
88
|
+
sprintId,
|
|
89
|
+
completedCount: completed.length,
|
|
90
|
+
incompleteCount: incomplete.length,
|
|
91
|
+
totalStories: stories.length,
|
|
92
|
+
doneSP: totalDoneSP,
|
|
93
|
+
totalSP,
|
|
94
|
+
completionRate: totalSP > 0 ? Math.round((totalDoneSP / totalSP) * 100) : 0,
|
|
95
|
+
}
|
|
96
|
+
}
|
|
@@ -0,0 +1,15 @@
|
|
|
1
|
+
{
|
|
2
|
+
"compilerOptions": {
|
|
3
|
+
"target": "ES2022",
|
|
4
|
+
"module": "ES2022",
|
|
5
|
+
"moduleResolution": "bundler",
|
|
6
|
+
"lib": ["ES2022"],
|
|
7
|
+
"types": ["@cloudflare/workers-types"],
|
|
8
|
+
"strict": true,
|
|
9
|
+
"esModuleInterop": true,
|
|
10
|
+
"skipLibCheck": true,
|
|
11
|
+
"noEmit": true
|
|
12
|
+
},
|
|
13
|
+
"include": ["src"],
|
|
14
|
+
"exclude": ["src/**/*.test.ts"]
|
|
15
|
+
}
|
|
@@ -0,0 +1,11 @@
|
|
|
1
|
+
name = "{{project.name}}-pm-api"
|
|
2
|
+
main = "src/index.ts"
|
|
3
|
+
compatibility_date = "2025-03-10"
|
|
4
|
+
|
|
5
|
+
# Database credentials: npx wrangler secret put TURSO_URL && npx wrangler secret put TURSO_AUTH_TOKEN
|
|
6
|
+
|
|
7
|
+
# Proactive Nudge schedule (UTC)
|
|
8
|
+
# 01:00 UTC: Morning check — review_overdue, sprint_deadline, task_stagnant, blocker_open
|
|
9
|
+
# 08:00 UTC: Afternoon check — all rules + standup_missing, sprint_daily_report
|
|
10
|
+
[triggers]
|
|
11
|
+
crons = ["0 1 * * *", "0 8 * * *"]
|
|
@@ -8,6 +8,9 @@
|
|
|
8
8
|
"name": "spec-site",
|
|
9
9
|
"version": "1.0.0",
|
|
10
10
|
"dependencies": {
|
|
11
|
+
"dompurify": "^3.2.0",
|
|
12
|
+
"lucide-vue-next": "^0.470.0",
|
|
13
|
+
"marked": "^15.0.0",
|
|
11
14
|
"vue": "^3.5.27",
|
|
12
15
|
"vue-router": "^4.5.0"
|
|
13
16
|
},
|
|
@@ -869,6 +872,13 @@
|
|
|
869
872
|
"dev": true,
|
|
870
873
|
"license": "MIT"
|
|
871
874
|
},
|
|
875
|
+
"node_modules/@types/trusted-types": {
|
|
876
|
+
"version": "2.0.7",
|
|
877
|
+
"resolved": "https://registry.npmjs.org/@types/trusted-types/-/trusted-types-2.0.7.tgz",
|
|
878
|
+
"integrity": "sha512-ScaPdn1dQczgbl0QFTeTOmVHFULt394XJgOQNoyVhZ6r2vLnMLJfBPd53SB52T/3G36VI1/g2MZaX0cwDuXsfw==",
|
|
879
|
+
"license": "MIT",
|
|
880
|
+
"optional": true
|
|
881
|
+
},
|
|
872
882
|
"node_modules/@vitejs/plugin-vue": {
|
|
873
883
|
"version": "5.2.4",
|
|
874
884
|
"resolved": "https://registry.npmjs.org/@vitejs/plugin-vue/-/plugin-vue-5.2.4.tgz",
|
|
@@ -1091,6 +1101,15 @@
|
|
|
1091
1101
|
"dev": true,
|
|
1092
1102
|
"license": "MIT"
|
|
1093
1103
|
},
|
|
1104
|
+
"node_modules/dompurify": {
|
|
1105
|
+
"version": "3.3.3",
|
|
1106
|
+
"resolved": "https://registry.npmjs.org/dompurify/-/dompurify-3.3.3.tgz",
|
|
1107
|
+
"integrity": "sha512-Oj6pzI2+RqBfFG+qOaOLbFXLQ90ARpcGG6UePL82bJLtdsa6CYJD7nmiU8MW9nQNOtCHV3lZ/Bzq1X0QYbBZCA==",
|
|
1108
|
+
"license": "(MPL-2.0 OR Apache-2.0)",
|
|
1109
|
+
"optionalDependencies": {
|
|
1110
|
+
"@types/trusted-types": "^2.0.7"
|
|
1111
|
+
}
|
|
1112
|
+
},
|
|
1094
1113
|
"node_modules/entities": {
|
|
1095
1114
|
"version": "7.0.1",
|
|
1096
1115
|
"resolved": "https://registry.npmjs.org/entities/-/entities-7.0.1.tgz",
|
|
@@ -1194,6 +1213,15 @@
|
|
|
1194
1213
|
"he": "bin/he"
|
|
1195
1214
|
}
|
|
1196
1215
|
},
|
|
1216
|
+
"node_modules/lucide-vue-next": {
|
|
1217
|
+
"version": "0.470.0",
|
|
1218
|
+
"resolved": "https://registry.npmjs.org/lucide-vue-next/-/lucide-vue-next-0.470.0.tgz",
|
|
1219
|
+
"integrity": "sha512-hqcVn93ghGJIEFo1MiQuy0PrZbp5nHZZcSxumZ+0qIRYy+f7e0ngVTsFOiQYL2Gl1YZ+PQR0WJkIDH5MCp3gGw==",
|
|
1220
|
+
"license": "ISC",
|
|
1221
|
+
"peerDependencies": {
|
|
1222
|
+
"vue": ">=3.0.1"
|
|
1223
|
+
}
|
|
1224
|
+
},
|
|
1197
1225
|
"node_modules/magic-string": {
|
|
1198
1226
|
"version": "0.30.21",
|
|
1199
1227
|
"resolved": "https://registry.npmjs.org/magic-string/-/magic-string-0.30.21.tgz",
|
|
@@ -1203,6 +1231,18 @@
|
|
|
1203
1231
|
"@jridgewell/sourcemap-codec": "^1.5.5"
|
|
1204
1232
|
}
|
|
1205
1233
|
},
|
|
1234
|
+
"node_modules/marked": {
|
|
1235
|
+
"version": "15.0.12",
|
|
1236
|
+
"resolved": "https://registry.npmjs.org/marked/-/marked-15.0.12.tgz",
|
|
1237
|
+
"integrity": "sha512-8dD6FusOQSrpv9Z1rdNMdlSgQOIP880DHqnohobOmYLElGEqAL/JvxvuxZO16r4HtjTlfPRDC1hbvxC9dPN2nA==",
|
|
1238
|
+
"license": "MIT",
|
|
1239
|
+
"bin": {
|
|
1240
|
+
"marked": "bin/marked.js"
|
|
1241
|
+
},
|
|
1242
|
+
"engines": {
|
|
1243
|
+
"node": ">= 18"
|
|
1244
|
+
}
|
|
1245
|
+
},
|
|
1206
1246
|
"node_modules/minimatch": {
|
|
1207
1247
|
"version": "9.0.9",
|
|
1208
1248
|
"resolved": "https://registry.npmjs.org/minimatch/-/minimatch-9.0.9.tgz",
|
|
@@ -122,6 +122,10 @@ export interface PmStoryRow {
|
|
|
122
122
|
priority: string
|
|
123
123
|
area: string
|
|
124
124
|
story_points: number | null
|
|
125
|
+
start_date: string | null
|
|
126
|
+
due_date: string | null
|
|
127
|
+
figma_url: string | null
|
|
128
|
+
related_prs: string | null
|
|
125
129
|
sort_order: number
|
|
126
130
|
created_at: string
|
|
127
131
|
updated_at: string
|
|
@@ -134,6 +138,8 @@ export interface PmTaskRow {
|
|
|
134
138
|
assignee: string | null
|
|
135
139
|
status: string
|
|
136
140
|
description: string | null
|
|
141
|
+
story_points: number | null
|
|
142
|
+
due_date: string | null
|
|
137
143
|
sort_order: number
|
|
138
144
|
created_at: string
|
|
139
145
|
updated_at: string
|