@commandgarden/cli 2.11.0 → 2.12.1
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/node_modules/@commandgarden/app/dist/client/assets/{Slides-BvMlkL-3.js → Slides-CHeVcB9K.js} +1 -1
- package/node_modules/@commandgarden/app/dist/client/assets/{index-wgb9-PIF.css → index-CDD2bVHm.css} +1 -1
- package/node_modules/@commandgarden/app/dist/client/assets/index-DR1TjI6k.js +511 -0
- package/node_modules/@commandgarden/app/dist/client/index.html +2 -2
- package/node_modules/@commandgarden/app/dist/server/journal/journal.service.js +65 -8
- package/node_modules/@commandgarden/app/dist/server/journal/journal.types.d.ts +15 -1
- package/node_modules/@commandgarden/app/dist/server/journal/sources/timetracking.source.js +16 -0
- package/node_modules/@commandgarden/daemon/connectors/ado-git-commits.yaml +1 -0
- package/package.json +1 -1
- package/node_modules/@commandgarden/app/dist/client/assets/index-BD8reQ8T.js +0 -496
|
@@ -10,8 +10,8 @@
|
|
|
10
10
|
<link rel="preconnect" href="https://fonts.gstatic.com" crossorigin />
|
|
11
11
|
<link href="https://fonts.googleapis.com/css2?family=Space+Grotesk:wght@400;500;600;700&family=JetBrains+Mono:wght@400;500;600&display=swap" rel="stylesheet" />
|
|
12
12
|
<title>commandGarden</title>
|
|
13
|
-
<script type="module" crossorigin src="/assets/index-
|
|
14
|
-
<link rel="stylesheet" crossorigin href="/assets/index-
|
|
13
|
+
<script type="module" crossorigin src="/assets/index-DR1TjI6k.js"></script>
|
|
14
|
+
<link rel="stylesheet" crossorigin href="/assets/index-CDD2bVHm.css">
|
|
15
15
|
</head>
|
|
16
16
|
<body>
|
|
17
17
|
<div id="root"></div>
|
|
@@ -122,22 +122,79 @@ export class JournalService {
|
|
|
122
122
|
generateBasicInsights(tt, mtg, jira, git, crossRef) {
|
|
123
123
|
const insights = [];
|
|
124
124
|
if (crossRef?.forgottenDays.length) {
|
|
125
|
-
insights.push(
|
|
125
|
+
insights.push({
|
|
126
|
+
id: 'forgotten-days',
|
|
127
|
+
severity: 'action',
|
|
128
|
+
category: 'time',
|
|
129
|
+
title: 'Unreleased hours',
|
|
130
|
+
detail: `Activity on ${crossRef.forgottenDays.join(', ')} but 0 hours logged — you may have forgotten to fill TimeTracking.`,
|
|
131
|
+
});
|
|
132
|
+
}
|
|
133
|
+
if (tt && tt.totalHours < tt.targetHours * 0.8) {
|
|
134
|
+
const gap = Math.round((tt.targetHours - tt.totalHours) * 100) / 100;
|
|
135
|
+
insights.push({
|
|
136
|
+
id: 'below-target',
|
|
137
|
+
severity: 'warning',
|
|
138
|
+
category: 'time',
|
|
139
|
+
title: 'Below weekly target',
|
|
140
|
+
detail: `${gap}h short of your ${tt.targetHours}h target.`,
|
|
141
|
+
});
|
|
126
142
|
}
|
|
127
143
|
if (crossRef?.heavyMeetingDays.length) {
|
|
128
144
|
const days = crossRef.heavyMeetingDays.map((d) => `${d.date} (${d.hours}h)`).join(', ');
|
|
129
|
-
insights.push(
|
|
145
|
+
insights.push({
|
|
146
|
+
id: 'heavy-meetings',
|
|
147
|
+
severity: 'warning',
|
|
148
|
+
category: 'meetings',
|
|
149
|
+
title: 'Heavy meeting days',
|
|
150
|
+
detail: `${days}. Consider blocking focus time.`,
|
|
151
|
+
});
|
|
130
152
|
}
|
|
131
|
-
if (
|
|
132
|
-
|
|
133
|
-
|
|
153
|
+
if (crossRef && crossRef.meetingRatio > 0.5 && mtg) {
|
|
154
|
+
insights.push({
|
|
155
|
+
id: 'high-meeting-ratio',
|
|
156
|
+
severity: 'info',
|
|
157
|
+
category: 'meetings',
|
|
158
|
+
title: 'High meeting ratio',
|
|
159
|
+
detail: `Meetings consumed ${Math.round(crossRef.meetingRatio * 100)}% of your logged hours this week.`,
|
|
160
|
+
});
|
|
134
161
|
}
|
|
135
162
|
if (jira?.blockers.length) {
|
|
136
163
|
const items = jira.blockers.map((b) => `${b.key} (${b.staleDays}d)`).join(', ');
|
|
137
|
-
insights.push(
|
|
164
|
+
insights.push({
|
|
165
|
+
id: 'stale-tickets',
|
|
166
|
+
severity: 'warning',
|
|
167
|
+
category: 'tickets',
|
|
168
|
+
title: 'Stale tickets',
|
|
169
|
+
detail: `${items}. Consider unblocking or reassigning.`,
|
|
170
|
+
});
|
|
138
171
|
}
|
|
139
|
-
if (crossRef && crossRef.
|
|
140
|
-
insights.push(
|
|
172
|
+
if (crossRef && crossRef.zeroCodingDays.length > 0 && git && git.totalCommits > 0) {
|
|
173
|
+
insights.push({
|
|
174
|
+
id: 'zero-coding-days',
|
|
175
|
+
severity: 'info',
|
|
176
|
+
category: 'code',
|
|
177
|
+
title: 'Zero-commit days',
|
|
178
|
+
detail: `No commits on ${crossRef.zeroCodingDays.join(', ')}.`,
|
|
179
|
+
});
|
|
180
|
+
}
|
|
181
|
+
if (git && git.totalCommits > 0 && git.totalPRsReviewed === 0) {
|
|
182
|
+
insights.push({
|
|
183
|
+
id: 'low-pr-reviews',
|
|
184
|
+
severity: 'info',
|
|
185
|
+
category: 'code',
|
|
186
|
+
title: 'No PR reviews',
|
|
187
|
+
detail: 'You made commits this week but reviewed 0 PRs.',
|
|
188
|
+
});
|
|
189
|
+
}
|
|
190
|
+
if (insights.length === 0) {
|
|
191
|
+
insights.push({
|
|
192
|
+
id: 'all-clear',
|
|
193
|
+
severity: 'positive',
|
|
194
|
+
category: 'time',
|
|
195
|
+
title: 'All clear',
|
|
196
|
+
detail: 'No issues detected this week.',
|
|
197
|
+
});
|
|
141
198
|
}
|
|
142
199
|
return insights;
|
|
143
200
|
}
|
|
@@ -35,6 +35,11 @@ export interface MonthlyTimetrackingData {
|
|
|
35
35
|
projectId: string;
|
|
36
36
|
hours: number;
|
|
37
37
|
}[];
|
|
38
|
+
hoursByProjectActivity: {
|
|
39
|
+
projectId: string;
|
|
40
|
+
activity: string;
|
|
41
|
+
hours: number;
|
|
42
|
+
}[];
|
|
38
43
|
}
|
|
39
44
|
export interface MeetingEntry {
|
|
40
45
|
date: string;
|
|
@@ -85,6 +90,15 @@ export interface GitData {
|
|
|
85
90
|
daily: GitDaily[];
|
|
86
91
|
repos: GitRepoActivity[];
|
|
87
92
|
}
|
|
93
|
+
export type InsightSeverity = 'action' | 'warning' | 'info' | 'positive';
|
|
94
|
+
export type InsightCategory = 'time' | 'meetings' | 'tickets' | 'code';
|
|
95
|
+
export interface Insight {
|
|
96
|
+
id: string;
|
|
97
|
+
severity: InsightSeverity;
|
|
98
|
+
category: InsightCategory;
|
|
99
|
+
title: string;
|
|
100
|
+
detail: string;
|
|
101
|
+
}
|
|
88
102
|
export interface CrossRefData {
|
|
89
103
|
forgottenDays: string[];
|
|
90
104
|
heavyMeetingDays: {
|
|
@@ -110,7 +124,7 @@ export interface JournalResponse {
|
|
|
110
124
|
jira: JiraData | null;
|
|
111
125
|
git: GitData | null;
|
|
112
126
|
crossRef: CrossRefData | null;
|
|
113
|
-
insights:
|
|
127
|
+
insights: Insight[];
|
|
114
128
|
errors: string[];
|
|
115
129
|
monthlyTimetracking: MonthlyTimetrackingData | null;
|
|
116
130
|
cache?: JournalCacheInfo;
|
|
@@ -115,16 +115,31 @@ export class TimetrackingSource {
|
|
|
115
115
|
const releasedDates = workingDatesElapsed.filter((d) => releasedDateSet.has(d));
|
|
116
116
|
const unreleasedDates = workingDatesElapsed.filter((d) => !releasedDateSet.has(d));
|
|
117
117
|
const hoursMap = new Map();
|
|
118
|
+
const hoursByPAMap = new Map();
|
|
118
119
|
for (const row of raw) {
|
|
119
120
|
if (!row.projectId)
|
|
120
121
|
continue;
|
|
121
122
|
const hrs = typeof row.hours === 'number' ? row.hours : 0;
|
|
122
123
|
hoursMap.set(row.projectId, (hoursMap.get(row.projectId) ?? 0) + hrs);
|
|
124
|
+
if (row.activity) {
|
|
125
|
+
const paKey = `${row.projectId}\0${row.activity}`;
|
|
126
|
+
const existing = hoursByPAMap.get(paKey);
|
|
127
|
+
if (existing) {
|
|
128
|
+
existing.hours += hrs;
|
|
129
|
+
}
|
|
130
|
+
else {
|
|
131
|
+
hoursByPAMap.set(paKey, { projectId: row.projectId, activity: row.activity, hours: hrs });
|
|
132
|
+
}
|
|
133
|
+
}
|
|
123
134
|
}
|
|
124
135
|
const hoursByProject = [...hoursMap.entries()].map(([projectId, hours]) => ({
|
|
125
136
|
projectId,
|
|
126
137
|
hours: Math.round(hours * 100) / 100,
|
|
127
138
|
}));
|
|
139
|
+
const hoursByProjectActivity = [...hoursByPAMap.values()].map((e) => ({
|
|
140
|
+
...e,
|
|
141
|
+
hours: Math.round(e.hours * 100) / 100,
|
|
142
|
+
}));
|
|
128
143
|
return {
|
|
129
144
|
month,
|
|
130
145
|
workingDaysTotal,
|
|
@@ -132,6 +147,7 @@ export class TimetrackingSource {
|
|
|
132
147
|
releasedDates,
|
|
133
148
|
unreleasedDates,
|
|
134
149
|
hoursByProject,
|
|
150
|
+
hoursByProjectActivity,
|
|
135
151
|
};
|
|
136
152
|
}
|
|
137
153
|
}
|