@ginkoai/cli 2.0.6 → 2.1.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/dist/commands/epic/index.d.ts +29 -0
- package/dist/commands/epic/index.d.ts.map +1 -0
- package/dist/commands/epic/index.js +94 -0
- package/dist/commands/epic/index.js.map +1 -0
- package/dist/commands/epic/status.d.ts +40 -0
- package/dist/commands/epic/status.d.ts.map +1 -0
- package/dist/commands/epic/status.js +244 -0
- package/dist/commands/epic/status.js.map +1 -0
- package/dist/commands/graph/api-client.d.ts +221 -1
- package/dist/commands/graph/api-client.d.ts.map +1 -1
- package/dist/commands/graph/api-client.js +141 -2
- package/dist/commands/graph/api-client.js.map +1 -1
- package/dist/commands/graph/load.d.ts.map +1 -1
- package/dist/commands/graph/load.js +40 -2
- package/dist/commands/graph/load.js.map +1 -1
- package/dist/commands/handoff.d.ts +3 -3
- package/dist/commands/handoff.d.ts.map +1 -1
- package/dist/commands/handoff.js +32 -3
- package/dist/commands/handoff.js.map +1 -1
- package/dist/commands/migrate/index.d.ts +27 -0
- package/dist/commands/migrate/index.d.ts.map +1 -0
- package/dist/commands/migrate/index.js +76 -0
- package/dist/commands/migrate/index.js.map +1 -0
- package/dist/commands/migrate/status-migration.d.ts +58 -0
- package/dist/commands/migrate/status-migration.d.ts.map +1 -0
- package/dist/commands/migrate/status-migration.js +323 -0
- package/dist/commands/migrate/status-migration.js.map +1 -0
- package/dist/commands/nudging/index.d.ts +24 -0
- package/dist/commands/nudging/index.d.ts.map +1 -0
- package/dist/commands/nudging/index.js +175 -0
- package/dist/commands/nudging/index.js.map +1 -0
- package/dist/commands/sprint/create.d.ts +26 -0
- package/dist/commands/sprint/create.d.ts.map +1 -0
- package/dist/commands/sprint/create.js +269 -0
- package/dist/commands/sprint/create.js.map +1 -0
- package/dist/commands/sprint/index.d.ts.map +1 -1
- package/dist/commands/sprint/index.js +28 -0
- package/dist/commands/sprint/index.js.map +1 -1
- package/dist/commands/sprint/quick-fix.d.ts +25 -0
- package/dist/commands/sprint/quick-fix.d.ts.map +1 -0
- package/dist/commands/sprint/quick-fix.js +151 -0
- package/dist/commands/sprint/quick-fix.js.map +1 -0
- package/dist/commands/sprint/sprint-pipeline-enhanced.d.ts.map +1 -1
- package/dist/commands/sprint/sprint-pipeline-enhanced.js +37 -0
- package/dist/commands/sprint/sprint-pipeline-enhanced.js.map +1 -1
- package/dist/commands/sprint/status.d.ts +42 -0
- package/dist/commands/sprint/status.d.ts.map +1 -0
- package/dist/commands/sprint/status.js +298 -0
- package/dist/commands/sprint/status.js.map +1 -0
- package/dist/commands/start/start-reflection.d.ts +53 -0
- package/dist/commands/start/start-reflection.d.ts.map +1 -1
- package/dist/commands/start/start-reflection.js +464 -71
- package/dist/commands/start/start-reflection.js.map +1 -1
- package/dist/commands/sync/sprint-syncer.d.ts +19 -12
- package/dist/commands/sync/sprint-syncer.d.ts.map +1 -1
- package/dist/commands/sync/sprint-syncer.js +58 -140
- package/dist/commands/sync/sprint-syncer.js.map +1 -1
- package/dist/commands/sync/sync-command.d.ts.map +1 -1
- package/dist/commands/sync/sync-command.js +6 -18
- package/dist/commands/sync/sync-command.js.map +1 -1
- package/dist/commands/task/index.d.ts +25 -0
- package/dist/commands/task/index.d.ts.map +1 -0
- package/dist/commands/task/index.js +100 -0
- package/dist/commands/task/index.js.map +1 -0
- package/dist/commands/task/status.d.ts +46 -0
- package/dist/commands/task/status.d.ts.map +1 -0
- package/dist/commands/task/status.js +348 -0
- package/dist/commands/task/status.js.map +1 -0
- package/dist/commands/team/index.d.ts +5 -0
- package/dist/commands/team/index.d.ts.map +1 -1
- package/dist/commands/team/index.js +28 -0
- package/dist/commands/team/index.js.map +1 -1
- package/dist/commands/team/status.d.ts +16 -0
- package/dist/commands/team/status.d.ts.map +1 -0
- package/dist/commands/team/status.js +180 -0
- package/dist/commands/team/status.js.map +1 -0
- package/dist/index.js +21 -32
- package/dist/index.js.map +1 -1
- package/dist/lib/adoption-score.d.ts +69 -0
- package/dist/lib/adoption-score.d.ts.map +1 -0
- package/dist/lib/adoption-score.js +206 -0
- package/dist/lib/adoption-score.js.map +1 -0
- package/dist/lib/coaching-level.d.ts +127 -0
- package/dist/lib/coaching-level.d.ts.map +1 -0
- package/dist/lib/coaching-level.js +406 -0
- package/dist/lib/coaching-level.js.map +1 -0
- package/dist/lib/context-loader-events.d.ts.map +1 -1
- package/dist/lib/context-loader-events.js +7 -26
- package/dist/lib/context-loader-events.js.map +1 -1
- package/dist/lib/event-logger.d.ts +42 -0
- package/dist/lib/event-logger.d.ts.map +1 -1
- package/dist/lib/event-logger.js +77 -0
- package/dist/lib/event-logger.js.map +1 -1
- package/dist/lib/output-formatter.d.ts +8 -2
- package/dist/lib/output-formatter.d.ts.map +1 -1
- package/dist/lib/output-formatter.js +98 -18
- package/dist/lib/output-formatter.js.map +1 -1
- package/dist/lib/pending-updates.d.ts +148 -0
- package/dist/lib/pending-updates.d.ts.map +1 -0
- package/dist/lib/pending-updates.js +301 -0
- package/dist/lib/pending-updates.js.map +1 -0
- package/dist/lib/planning-menu.d.ts +69 -0
- package/dist/lib/planning-menu.d.ts.map +1 -0
- package/dist/lib/planning-menu.js +342 -0
- package/dist/lib/planning-menu.js.map +1 -0
- package/dist/lib/sprint-loader.d.ts +86 -14
- package/dist/lib/sprint-loader.d.ts.map +1 -1
- package/dist/lib/sprint-loader.js +293 -98
- package/dist/lib/sprint-loader.js.map +1 -1
- package/dist/lib/state-cache.d.ts +142 -0
- package/dist/lib/state-cache.d.ts.map +1 -0
- package/dist/lib/state-cache.js +259 -0
- package/dist/lib/state-cache.js.map +1 -0
- package/dist/lib/targeted-coaching.d.ts +71 -0
- package/dist/lib/targeted-coaching.d.ts.map +1 -0
- package/dist/lib/targeted-coaching.js +318 -0
- package/dist/lib/targeted-coaching.js.map +1 -0
- package/dist/lib/task-graph-sync.d.ts +105 -0
- package/dist/lib/task-graph-sync.d.ts.map +1 -0
- package/dist/lib/task-graph-sync.js +178 -0
- package/dist/lib/task-graph-sync.js.map +1 -0
- package/dist/lib/task-parser.d.ts +109 -0
- package/dist/lib/task-parser.d.ts.map +1 -0
- package/dist/lib/task-parser.js +407 -0
- package/dist/lib/task-parser.js.map +1 -0
- package/dist/lib/user-sprint.d.ts +53 -0
- package/dist/lib/user-sprint.d.ts.map +1 -1
- package/dist/lib/user-sprint.js +137 -2
- package/dist/lib/user-sprint.js.map +1 -1
- package/dist/lib/work-reconciliation.d.ts +59 -0
- package/dist/lib/work-reconciliation.d.ts.map +1 -0
- package/dist/lib/work-reconciliation.js +267 -0
- package/dist/lib/work-reconciliation.js.map +1 -0
- package/dist/templates/ai-instructions-template.d.ts.map +1 -1
- package/dist/templates/ai-instructions-template.js +7 -5
- package/dist/templates/ai-instructions-template.js.map +1 -1
- package/dist/templates/epic-template.md +0 -2
- package/dist/types/config.d.ts.map +1 -1
- package/dist/types/config.js +7 -5
- package/dist/types/config.js.map +1 -1
- package/dist/utils/synthesis.d.ts +4 -0
- package/dist/utils/synthesis.d.ts.map +1 -1
- package/dist/utils/synthesis.js +12 -18
- package/dist/utils/synthesis.js.map +1 -1
- package/dist/utils/version-check.d.ts +26 -0
- package/dist/utils/version-check.d.ts.map +1 -0
- package/dist/utils/version-check.js +186 -0
- package/dist/utils/version-check.js.map +1 -0
- package/package.json +2 -2
|
@@ -0,0 +1,318 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* @fileType: utility
|
|
3
|
+
* @status: current
|
|
4
|
+
* @updated: 2026-01-26
|
|
5
|
+
* @tags: [coaching, insights, targeted, adaptive, epic-016-s05]
|
|
6
|
+
* @related: [coaching-level.ts, start-reflection.ts, handoff.ts]
|
|
7
|
+
* @priority: medium
|
|
8
|
+
* @complexity: medium
|
|
9
|
+
* @dependencies: [fs-extra, path]
|
|
10
|
+
*/
|
|
11
|
+
/**
|
|
12
|
+
* Targeted Coaching Elaborations (EPIC-016 Sprint 5 Task 3)
|
|
13
|
+
*
|
|
14
|
+
* When a specific metric is low, provides focused coaching in that area.
|
|
15
|
+
*
|
|
16
|
+
* Metric-Specific Coaching:
|
|
17
|
+
* | Low Metric | Coaching Focus |
|
|
18
|
+
* |----------------------|---------------------------------------------------------|
|
|
19
|
+
* | Session Efficiency | "Consider using `ginko handoff` to preserve context" |
|
|
20
|
+
* | Pattern Adoption | Extra guidance on Epic→Sprint→Task structure |
|
|
21
|
+
* | Collaboration Quality| Prompts about logging decisions, handoff quality |
|
|
22
|
+
* | Anti-Patterns | Specific warnings about detected anti-patterns |
|
|
23
|
+
*
|
|
24
|
+
* Features:
|
|
25
|
+
* - Track which tips shown to avoid repetition
|
|
26
|
+
* - Inject tips at relevant moments (start, handoff)
|
|
27
|
+
* - No tip spam (shown once per session max)
|
|
28
|
+
*/
|
|
29
|
+
import fs from 'fs-extra';
|
|
30
|
+
import path from 'path';
|
|
31
|
+
import chalk from 'chalk';
|
|
32
|
+
import { getUserEmail, getGinkoDir } from '../utils/helpers.js';
|
|
33
|
+
import { isMetricLow } from './coaching-level.js';
|
|
34
|
+
import { logTargetedTipShown } from './event-logger.js';
|
|
35
|
+
// =============================================================================
|
|
36
|
+
// Constants
|
|
37
|
+
// =============================================================================
|
|
38
|
+
const TIPS_RECORD_FILE = 'shown-tips.json';
|
|
39
|
+
const LOW_THRESHOLD = 70;
|
|
40
|
+
/**
|
|
41
|
+
* All available coaching tips organized by metric
|
|
42
|
+
*/
|
|
43
|
+
export const COACHING_TIPS = [
|
|
44
|
+
// Session Efficiency Tips
|
|
45
|
+
{
|
|
46
|
+
id: 'efficiency-handoff',
|
|
47
|
+
metric: 'sessionEfficiency',
|
|
48
|
+
context: ['start', 'handoff'],
|
|
49
|
+
message: 'Consider using `ginko handoff` to preserve context between sessions',
|
|
50
|
+
action: 'ginko handoff',
|
|
51
|
+
priority: 10,
|
|
52
|
+
},
|
|
53
|
+
{
|
|
54
|
+
id: 'efficiency-context-loading',
|
|
55
|
+
metric: 'sessionEfficiency',
|
|
56
|
+
context: ['start'],
|
|
57
|
+
message: 'Sessions with good handoffs start 40% faster on average',
|
|
58
|
+
priority: 5,
|
|
59
|
+
},
|
|
60
|
+
{
|
|
61
|
+
id: 'efficiency-log-decisions',
|
|
62
|
+
metric: 'sessionEfficiency',
|
|
63
|
+
context: ['handoff'],
|
|
64
|
+
message: 'Log key decisions with `ginko log` before handoff for better context transfer',
|
|
65
|
+
action: 'ginko log',
|
|
66
|
+
priority: 8,
|
|
67
|
+
},
|
|
68
|
+
// Pattern Adoption Tips
|
|
69
|
+
{
|
|
70
|
+
id: 'patterns-structure',
|
|
71
|
+
metric: 'patternAdoption',
|
|
72
|
+
context: ['start', 'planning'],
|
|
73
|
+
message: 'Try organizing work into Epic→Sprint→Task structure for better tracking',
|
|
74
|
+
priority: 10,
|
|
75
|
+
},
|
|
76
|
+
{
|
|
77
|
+
id: 'patterns-sprint-create',
|
|
78
|
+
metric: 'patternAdoption',
|
|
79
|
+
context: ['planning'],
|
|
80
|
+
message: 'Use `ginko sprint create` to break down work into trackable tasks',
|
|
81
|
+
action: 'ginko sprint create',
|
|
82
|
+
priority: 8,
|
|
83
|
+
},
|
|
84
|
+
{
|
|
85
|
+
id: 'patterns-quick-fix',
|
|
86
|
+
metric: 'patternAdoption',
|
|
87
|
+
context: ['start'],
|
|
88
|
+
message: 'For small fixes, try `ginko sprint qf "description"` for minimal tracking overhead',
|
|
89
|
+
action: 'ginko sprint qf',
|
|
90
|
+
priority: 6,
|
|
91
|
+
},
|
|
92
|
+
// Collaboration Quality Tips
|
|
93
|
+
{
|
|
94
|
+
id: 'quality-log-decisions',
|
|
95
|
+
metric: 'collaborationQuality',
|
|
96
|
+
context: ['start', 'task_complete'],
|
|
97
|
+
message: 'Log important decisions with `ginko log` to help future collaborators',
|
|
98
|
+
action: 'ginko log',
|
|
99
|
+
priority: 10,
|
|
100
|
+
},
|
|
101
|
+
{
|
|
102
|
+
id: 'quality-handoff-content',
|
|
103
|
+
metric: 'collaborationQuality',
|
|
104
|
+
context: ['handoff'],
|
|
105
|
+
message: 'Include what you learned, not just what you did, in handoffs',
|
|
106
|
+
priority: 8,
|
|
107
|
+
},
|
|
108
|
+
{
|
|
109
|
+
id: 'quality-team-sync',
|
|
110
|
+
metric: 'collaborationQuality',
|
|
111
|
+
context: ['start'],
|
|
112
|
+
message: 'Run `ginko sync` periodically to stay aligned with team updates',
|
|
113
|
+
action: 'ginko sync',
|
|
114
|
+
priority: 6,
|
|
115
|
+
},
|
|
116
|
+
// Anti-Patterns Tips
|
|
117
|
+
{
|
|
118
|
+
id: 'antipatterns-review',
|
|
119
|
+
metric: 'antiPatterns',
|
|
120
|
+
context: ['start'],
|
|
121
|
+
message: 'Review recent gotcha warnings - you may be hitting known issues',
|
|
122
|
+
priority: 10,
|
|
123
|
+
},
|
|
124
|
+
{
|
|
125
|
+
id: 'antipatterns-patterns',
|
|
126
|
+
metric: 'antiPatterns',
|
|
127
|
+
context: ['start', 'task_complete'],
|
|
128
|
+
message: 'Check task patterns with `ginko graph explore <task-id>` for guidance',
|
|
129
|
+
action: 'ginko graph explore',
|
|
130
|
+
priority: 8,
|
|
131
|
+
},
|
|
132
|
+
{
|
|
133
|
+
id: 'antipatterns-adr',
|
|
134
|
+
metric: 'antiPatterns',
|
|
135
|
+
context: ['start'],
|
|
136
|
+
message: 'ADR constraints on your current task may help avoid common pitfalls',
|
|
137
|
+
priority: 6,
|
|
138
|
+
},
|
|
139
|
+
];
|
|
140
|
+
// =============================================================================
|
|
141
|
+
// Shown Tips Tracking
|
|
142
|
+
// =============================================================================
|
|
143
|
+
async function getShownTipsPath() {
|
|
144
|
+
const ginkoDir = await getGinkoDir();
|
|
145
|
+
const userEmail = await getUserEmail();
|
|
146
|
+
const userSlug = userEmail.replace('@', '-at-').replace(/\./g, '-');
|
|
147
|
+
return path.join(ginkoDir, 'sessions', userSlug, TIPS_RECORD_FILE);
|
|
148
|
+
}
|
|
149
|
+
async function loadShownTips() {
|
|
150
|
+
const filePath = await getShownTipsPath();
|
|
151
|
+
try {
|
|
152
|
+
if (await fs.pathExists(filePath)) {
|
|
153
|
+
const data = await fs.readJSON(filePath);
|
|
154
|
+
// Check if this is the same session (within 8 hours)
|
|
155
|
+
const lastUpdated = new Date(data.lastUpdated).getTime();
|
|
156
|
+
const now = Date.now();
|
|
157
|
+
const eightHours = 8 * 60 * 60 * 1000;
|
|
158
|
+
if (now - lastUpdated < eightHours) {
|
|
159
|
+
return data;
|
|
160
|
+
}
|
|
161
|
+
}
|
|
162
|
+
}
|
|
163
|
+
catch {
|
|
164
|
+
// File corrupted or invalid
|
|
165
|
+
}
|
|
166
|
+
// Start fresh session
|
|
167
|
+
return {
|
|
168
|
+
sessionId: generateSessionId(),
|
|
169
|
+
shownTipIds: [],
|
|
170
|
+
lastUpdated: new Date().toISOString(),
|
|
171
|
+
};
|
|
172
|
+
}
|
|
173
|
+
async function saveShownTips(record) {
|
|
174
|
+
const filePath = await getShownTipsPath();
|
|
175
|
+
await fs.ensureDir(path.dirname(filePath));
|
|
176
|
+
record.lastUpdated = new Date().toISOString();
|
|
177
|
+
await fs.writeJSON(filePath, record, { spaces: 2 });
|
|
178
|
+
}
|
|
179
|
+
function generateSessionId() {
|
|
180
|
+
return `session-${Date.now()}-${Math.random().toString(36).substr(2, 9)}`;
|
|
181
|
+
}
|
|
182
|
+
async function markTipAsShown(tipId) {
|
|
183
|
+
const record = await loadShownTips();
|
|
184
|
+
if (!record.shownTipIds.includes(tipId)) {
|
|
185
|
+
record.shownTipIds.push(tipId);
|
|
186
|
+
await saveShownTips(record);
|
|
187
|
+
}
|
|
188
|
+
}
|
|
189
|
+
async function isTipShown(tipId) {
|
|
190
|
+
const record = await loadShownTips();
|
|
191
|
+
return record.shownTipIds.includes(tipId);
|
|
192
|
+
}
|
|
193
|
+
// =============================================================================
|
|
194
|
+
// Tip Selection
|
|
195
|
+
// =============================================================================
|
|
196
|
+
/**
|
|
197
|
+
* Get applicable tips for a given context and coaching context
|
|
198
|
+
*
|
|
199
|
+
* @param coachingCtx - Coaching context with metric scores
|
|
200
|
+
* @param context - Current context (start, handoff, etc.)
|
|
201
|
+
* @param limit - Maximum number of tips to return
|
|
202
|
+
* @returns Array of applicable tips, prioritized
|
|
203
|
+
*/
|
|
204
|
+
export async function getApplicableTips(coachingCtx, context, limit = 1) {
|
|
205
|
+
// Only show tips in supportive or standard mode
|
|
206
|
+
if (coachingCtx.level === 'minimal') {
|
|
207
|
+
return [];
|
|
208
|
+
}
|
|
209
|
+
const applicableTips = [];
|
|
210
|
+
// Find tips for low metrics
|
|
211
|
+
for (const tip of COACHING_TIPS) {
|
|
212
|
+
// Check if tip applies to this context
|
|
213
|
+
if (!tip.context.includes(context)) {
|
|
214
|
+
continue;
|
|
215
|
+
}
|
|
216
|
+
// Check if the metric is low
|
|
217
|
+
const metricValue = getMetricValue(coachingCtx, tip.metric);
|
|
218
|
+
if (!isMetricLow(metricValue, LOW_THRESHOLD)) {
|
|
219
|
+
continue;
|
|
220
|
+
}
|
|
221
|
+
// Check if already shown this session
|
|
222
|
+
if (await isTipShown(tip.id)) {
|
|
223
|
+
continue;
|
|
224
|
+
}
|
|
225
|
+
applicableTips.push(tip);
|
|
226
|
+
}
|
|
227
|
+
// Sort by priority (highest first) and limit
|
|
228
|
+
return applicableTips
|
|
229
|
+
.sort((a, b) => b.priority - a.priority)
|
|
230
|
+
.slice(0, limit);
|
|
231
|
+
}
|
|
232
|
+
function getMetricValue(ctx, metric) {
|
|
233
|
+
switch (metric) {
|
|
234
|
+
case 'sessionEfficiency':
|
|
235
|
+
return ctx.metrics.sessionEfficiency;
|
|
236
|
+
case 'patternAdoption':
|
|
237
|
+
return ctx.metrics.patternAdoption;
|
|
238
|
+
case 'collaborationQuality':
|
|
239
|
+
return ctx.metrics.collaborationQuality;
|
|
240
|
+
case 'antiPatterns':
|
|
241
|
+
return ctx.metrics.antiPatterns;
|
|
242
|
+
}
|
|
243
|
+
}
|
|
244
|
+
// =============================================================================
|
|
245
|
+
// Display Functions
|
|
246
|
+
// =============================================================================
|
|
247
|
+
/**
|
|
248
|
+
* Display a coaching tip to the console
|
|
249
|
+
*/
|
|
250
|
+
export function displayTip(tip) {
|
|
251
|
+
const icon = getTipIcon(tip.metric);
|
|
252
|
+
console.log(chalk.cyan(`${icon} Coaching tip:`));
|
|
253
|
+
console.log(chalk.white(` ${tip.message}`));
|
|
254
|
+
if (tip.action) {
|
|
255
|
+
console.log(chalk.dim(` Try: ${tip.action}`));
|
|
256
|
+
}
|
|
257
|
+
console.log('');
|
|
258
|
+
}
|
|
259
|
+
/**
|
|
260
|
+
* Show targeted coaching tips for the current context
|
|
261
|
+
*
|
|
262
|
+
* @param coachingCtx - Coaching context with metric scores
|
|
263
|
+
* @param context - Current context
|
|
264
|
+
* @returns Number of tips shown
|
|
265
|
+
*/
|
|
266
|
+
export async function showTargetedCoaching(coachingCtx, context) {
|
|
267
|
+
const tips = await getApplicableTips(coachingCtx, context);
|
|
268
|
+
for (const tip of tips) {
|
|
269
|
+
displayTip(tip);
|
|
270
|
+
await markTipAsShown(tip.id);
|
|
271
|
+
// EPIC-016 Sprint 5 t05: Log tip shown for feedback loop
|
|
272
|
+
logTargetedTipShown(tip.id, tip.metric, coachingCtx.level).catch(() => {
|
|
273
|
+
// Non-critical - don't fail on logging errors
|
|
274
|
+
});
|
|
275
|
+
}
|
|
276
|
+
return tips.length;
|
|
277
|
+
}
|
|
278
|
+
/**
|
|
279
|
+
* Get coaching tip for a specific metric (for inline use)
|
|
280
|
+
*/
|
|
281
|
+
export async function getTipForMetric(coachingCtx, metric, context) {
|
|
282
|
+
const tips = await getApplicableTips(coachingCtx, context);
|
|
283
|
+
const tip = tips.find(t => t.metric === metric);
|
|
284
|
+
return tip ? tip.message : null;
|
|
285
|
+
}
|
|
286
|
+
function getTipIcon(metric) {
|
|
287
|
+
switch (metric) {
|
|
288
|
+
case 'sessionEfficiency':
|
|
289
|
+
return '⚡';
|
|
290
|
+
case 'patternAdoption':
|
|
291
|
+
return '📋';
|
|
292
|
+
case 'collaborationQuality':
|
|
293
|
+
return '🤝';
|
|
294
|
+
case 'antiPatterns':
|
|
295
|
+
return '⚠️';
|
|
296
|
+
}
|
|
297
|
+
}
|
|
298
|
+
// =============================================================================
|
|
299
|
+
// Metric Display Names
|
|
300
|
+
// =============================================================================
|
|
301
|
+
export const METRIC_DISPLAY_NAMES = {
|
|
302
|
+
sessionEfficiency: 'Session Efficiency',
|
|
303
|
+
patternAdoption: 'Pattern Adoption',
|
|
304
|
+
collaborationQuality: 'Collaboration Quality',
|
|
305
|
+
antiPatterns: 'Anti-Patterns',
|
|
306
|
+
};
|
|
307
|
+
// =============================================================================
|
|
308
|
+
// Testing Exports
|
|
309
|
+
// =============================================================================
|
|
310
|
+
export const __testing = {
|
|
311
|
+
LOW_THRESHOLD,
|
|
312
|
+
loadShownTips,
|
|
313
|
+
saveShownTips,
|
|
314
|
+
markTipAsShown,
|
|
315
|
+
isTipShown,
|
|
316
|
+
getMetricValue,
|
|
317
|
+
};
|
|
318
|
+
//# sourceMappingURL=targeted-coaching.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"targeted-coaching.js","sourceRoot":"","sources":["../../src/lib/targeted-coaching.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,105 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* @fileType: utility
|
|
3
|
+
* @status: current
|
|
4
|
+
* @updated: 2026-01-19
|
|
5
|
+
* @tags: [task-sync, graph, neo4j, epic-015, sprint-0a]
|
|
6
|
+
* @related: [task-parser.ts, ../commands/graph/api-client.ts]
|
|
7
|
+
* @priority: high
|
|
8
|
+
* @complexity: medium
|
|
9
|
+
* @dependencies: [api-client]
|
|
10
|
+
*/
|
|
11
|
+
/**
|
|
12
|
+
* Task Graph Sync (EPIC-015 Sprint 0a Tasks 2-3)
|
|
13
|
+
*
|
|
14
|
+
* Syncs parsed tasks to Neo4j graph via the dashboard API.
|
|
15
|
+
* Creates Task nodes and BELONGS_TO relationships.
|
|
16
|
+
*
|
|
17
|
+
* Key principle (ADR-060): Content from Git, State from Graph.
|
|
18
|
+
* - On CREATE: Uses initial_status from markdown
|
|
19
|
+
* - On UPDATE: Preserves existing status (graph-authoritative)
|
|
20
|
+
*/
|
|
21
|
+
import { GraphApiClient } from '../commands/graph/api-client.js';
|
|
22
|
+
import { ParsedTask, SprintParseResult } from './task-parser.js';
|
|
23
|
+
/**
|
|
24
|
+
* Response from task sync API
|
|
25
|
+
*/
|
|
26
|
+
export interface TaskSyncResponse {
|
|
27
|
+
success: boolean;
|
|
28
|
+
created: number;
|
|
29
|
+
updated: number;
|
|
30
|
+
relationships: number;
|
|
31
|
+
tasks: string[];
|
|
32
|
+
}
|
|
33
|
+
/**
|
|
34
|
+
* Options for task sync
|
|
35
|
+
*/
|
|
36
|
+
export interface TaskSyncOptions {
|
|
37
|
+
/** Create BELONGS_TO relationships (default: true) */
|
|
38
|
+
createRelationships?: boolean;
|
|
39
|
+
/** Batch size for API calls (default: 50) */
|
|
40
|
+
batchSize?: number;
|
|
41
|
+
/** Progress callback */
|
|
42
|
+
onProgress?: (synced: number, total: number) => void;
|
|
43
|
+
}
|
|
44
|
+
/**
|
|
45
|
+
* Result of syncing multiple sprints
|
|
46
|
+
*/
|
|
47
|
+
export interface BatchSyncResult {
|
|
48
|
+
success: boolean;
|
|
49
|
+
totalTasks: number;
|
|
50
|
+
created: number;
|
|
51
|
+
updated: number;
|
|
52
|
+
relationships: number;
|
|
53
|
+
errors: string[];
|
|
54
|
+
}
|
|
55
|
+
/**
|
|
56
|
+
* Sync tasks to graph via API
|
|
57
|
+
*
|
|
58
|
+
* @param tasks - Array of parsed tasks
|
|
59
|
+
* @param graphId - Graph namespace ID
|
|
60
|
+
* @param client - GraphApiClient instance
|
|
61
|
+
* @param options - Sync options
|
|
62
|
+
* @returns TaskSyncResponse
|
|
63
|
+
*/
|
|
64
|
+
export declare function syncTasksToGraph(tasks: ParsedTask[], graphId: string, client: GraphApiClient, options?: TaskSyncOptions): Promise<TaskSyncResponse>;
|
|
65
|
+
/**
|
|
66
|
+
* Sync a single sprint's tasks to graph
|
|
67
|
+
*
|
|
68
|
+
* @param sprintResult - Parsed sprint with tasks
|
|
69
|
+
* @param client - GraphApiClient instance (optional, will create if not provided)
|
|
70
|
+
* @param options - Sync options
|
|
71
|
+
* @returns TaskSyncResponse
|
|
72
|
+
*/
|
|
73
|
+
export declare function syncSprintTasksToGraph(sprintResult: SprintParseResult, client?: GraphApiClient, options?: TaskSyncOptions): Promise<TaskSyncResponse>;
|
|
74
|
+
/**
|
|
75
|
+
* Sync multiple sprints' tasks to graph
|
|
76
|
+
*
|
|
77
|
+
* @param sprintResults - Array of parsed sprints with tasks
|
|
78
|
+
* @param options - Sync options
|
|
79
|
+
* @returns BatchSyncResult
|
|
80
|
+
*/
|
|
81
|
+
export declare function syncAllSprintTasksToGraph(sprintResults: SprintParseResult[], options?: TaskSyncOptions): Promise<BatchSyncResult>;
|
|
82
|
+
/**
|
|
83
|
+
* Get task sync status from graph
|
|
84
|
+
*
|
|
85
|
+
* @param graphId - Graph namespace ID
|
|
86
|
+
* @param sprintId - Optional sprint ID filter
|
|
87
|
+
* @param epicId - Optional epic ID filter
|
|
88
|
+
* @param client - GraphApiClient instance
|
|
89
|
+
* @returns Array of task status objects
|
|
90
|
+
*/
|
|
91
|
+
export declare function getTasksFromGraph(graphId: string, client: GraphApiClient, filters?: {
|
|
92
|
+
sprintId?: string;
|
|
93
|
+
epicId?: string;
|
|
94
|
+
}): Promise<Array<{
|
|
95
|
+
id: string;
|
|
96
|
+
title: string;
|
|
97
|
+
status: string;
|
|
98
|
+
priority: string;
|
|
99
|
+
sprint_id: string;
|
|
100
|
+
epic_id: string;
|
|
101
|
+
estimate: string | null;
|
|
102
|
+
assignee: string | null;
|
|
103
|
+
synced_at: string | null;
|
|
104
|
+
}>>;
|
|
105
|
+
//# sourceMappingURL=task-graph-sync.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"task-graph-sync.d.ts","sourceRoot":"","sources":["../../src/lib/task-graph-sync.ts"],"names":[],"mappings":"AAAA;;;;;;;;;GASG;AAEH;;;;;;;;;GASG;AAEH,OAAO,EAAE,cAAc,EAAE,MAAM,iCAAiC,CAAC;AAEjE,OAAO,EAAE,UAAU,EAAE,iBAAiB,EAAE,MAAM,kBAAkB,CAAC;AAEjE;;GAEG;AACH,MAAM,WAAW,gBAAgB;IAC/B,OAAO,EAAE,OAAO,CAAC;IACjB,OAAO,EAAE,MAAM,CAAC;IAChB,OAAO,EAAE,MAAM,CAAC;IAChB,aAAa,EAAE,MAAM,CAAC;IACtB,KAAK,EAAE,MAAM,EAAE,CAAC;CACjB;AAED;;GAEG;AACH,MAAM,WAAW,eAAe;IAC9B,sDAAsD;IACtD,mBAAmB,CAAC,EAAE,OAAO,CAAC;IAC9B,6CAA6C;IAC7C,SAAS,CAAC,EAAE,MAAM,CAAC;IACnB,wBAAwB;IACxB,UAAU,CAAC,EAAE,CAAC,MAAM,EAAE,MAAM,EAAE,KAAK,EAAE,MAAM,KAAK,IAAI,CAAC;CACtD;AAED;;GAEG;AACH,MAAM,WAAW,eAAe;IAC9B,OAAO,EAAE,OAAO,CAAC;IACjB,UAAU,EAAE,MAAM,CAAC;IACnB,OAAO,EAAE,MAAM,CAAC;IAChB,OAAO,EAAE,MAAM,CAAC;IAChB,aAAa,EAAE,MAAM,CAAC;IACtB,MAAM,EAAE,MAAM,EAAE,CAAC;CAClB;AAED;;;;;;;;GAQG;AACH,wBAAsB,gBAAgB,CACpC,KAAK,EAAE,UAAU,EAAE,EACnB,OAAO,EAAE,MAAM,EACf,MAAM,EAAE,cAAc,EACtB,OAAO,GAAE,eAAoB,GAC5B,OAAO,CAAC,gBAAgB,CAAC,CA+C3B;AAED;;;;;;;GAOG;AACH,wBAAsB,sBAAsB,CAC1C,YAAY,EAAE,iBAAiB,EAC/B,MAAM,CAAC,EAAE,cAAc,EACvB,OAAO,GAAE,eAAoB,GAC5B,OAAO,CAAC,gBAAgB,CAAC,CAgB3B;AAED;;;;;;GAMG;AACH,wBAAsB,yBAAyB,CAC7C,aAAa,EAAE,iBAAiB,EAAE,EAClC,OAAO,GAAE,eAAoB,GAC5B,OAAO,CAAC,eAAe,CAAC,CAqE1B;AAED;;;;;;;;GAQG;AACH,wBAAsB,iBAAiB,CACrC,OAAO,EAAE,MAAM,EACf,MAAM,EAAE,cAAc,EACtB,OAAO,CAAC,EAAE;IAAE,QAAQ,CAAC,EAAE,MAAM,CAAC;IAAC,MAAM,CAAC,EAAE,MAAM,CAAA;CAAE,GAC/C,OAAO,CAAC,KAAK,CAAC;IACf,EAAE,EAAE,MAAM,CAAC;IACX,KAAK,EAAE,MAAM,CAAC;IACd,MAAM,EAAE,MAAM,CAAC;IACf,QAAQ,EAAE,MAAM,CAAC;IACjB,SAAS,EAAE,MAAM,CAAC;IAClB,OAAO,EAAE,MAAM,CAAC;IAChB,QAAQ,EAAE,MAAM,GAAG,IAAI,CAAC;IACxB,QAAQ,EAAE,MAAM,GAAG,IAAI,CAAC;IACxB,SAAS,EAAE,MAAM,GAAG,IAAI,CAAC;CAC1B,CAAC,CAAC,CAEF"}
|
|
@@ -0,0 +1,178 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* @fileType: utility
|
|
3
|
+
* @status: current
|
|
4
|
+
* @updated: 2026-01-19
|
|
5
|
+
* @tags: [task-sync, graph, neo4j, epic-015, sprint-0a]
|
|
6
|
+
* @related: [task-parser.ts, ../commands/graph/api-client.ts]
|
|
7
|
+
* @priority: high
|
|
8
|
+
* @complexity: medium
|
|
9
|
+
* @dependencies: [api-client]
|
|
10
|
+
*/
|
|
11
|
+
/**
|
|
12
|
+
* Task Graph Sync (EPIC-015 Sprint 0a Tasks 2-3)
|
|
13
|
+
*
|
|
14
|
+
* Syncs parsed tasks to Neo4j graph via the dashboard API.
|
|
15
|
+
* Creates Task nodes and BELONGS_TO relationships.
|
|
16
|
+
*
|
|
17
|
+
* Key principle (ADR-060): Content from Git, State from Graph.
|
|
18
|
+
* - On CREATE: Uses initial_status from markdown
|
|
19
|
+
* - On UPDATE: Preserves existing status (graph-authoritative)
|
|
20
|
+
*/
|
|
21
|
+
import { GraphApiClient } from '../commands/graph/api-client.js';
|
|
22
|
+
import { loadGraphConfig, isGraphInitialized } from '../commands/graph/config.js';
|
|
23
|
+
/**
|
|
24
|
+
* Sync tasks to graph via API
|
|
25
|
+
*
|
|
26
|
+
* @param tasks - Array of parsed tasks
|
|
27
|
+
* @param graphId - Graph namespace ID
|
|
28
|
+
* @param client - GraphApiClient instance
|
|
29
|
+
* @param options - Sync options
|
|
30
|
+
* @returns TaskSyncResponse
|
|
31
|
+
*/
|
|
32
|
+
export async function syncTasksToGraph(tasks, graphId, client, options = {}) {
|
|
33
|
+
const { createRelationships = true, batchSize = 50, onProgress } = options;
|
|
34
|
+
if (tasks.length === 0) {
|
|
35
|
+
return {
|
|
36
|
+
success: true,
|
|
37
|
+
created: 0,
|
|
38
|
+
updated: 0,
|
|
39
|
+
relationships: 0,
|
|
40
|
+
tasks: [],
|
|
41
|
+
};
|
|
42
|
+
}
|
|
43
|
+
// Process in batches
|
|
44
|
+
const batches = [];
|
|
45
|
+
for (let i = 0; i < tasks.length; i += batchSize) {
|
|
46
|
+
batches.push(tasks.slice(i, i + batchSize));
|
|
47
|
+
}
|
|
48
|
+
let totalCreated = 0;
|
|
49
|
+
let totalUpdated = 0;
|
|
50
|
+
let totalRelationships = 0;
|
|
51
|
+
const allTaskIds = [];
|
|
52
|
+
for (let i = 0; i < batches.length; i++) {
|
|
53
|
+
const batch = batches[i];
|
|
54
|
+
const response = await client.syncTasks(graphId, batch, createRelationships);
|
|
55
|
+
totalCreated += response.created;
|
|
56
|
+
totalUpdated += response.updated;
|
|
57
|
+
totalRelationships += response.relationships;
|
|
58
|
+
allTaskIds.push(...response.tasks);
|
|
59
|
+
if (onProgress) {
|
|
60
|
+
const synced = Math.min((i + 1) * batchSize, tasks.length);
|
|
61
|
+
onProgress(synced, tasks.length);
|
|
62
|
+
}
|
|
63
|
+
}
|
|
64
|
+
return {
|
|
65
|
+
success: true,
|
|
66
|
+
created: totalCreated,
|
|
67
|
+
updated: totalUpdated,
|
|
68
|
+
relationships: totalRelationships,
|
|
69
|
+
tasks: allTaskIds,
|
|
70
|
+
};
|
|
71
|
+
}
|
|
72
|
+
/**
|
|
73
|
+
* Sync a single sprint's tasks to graph
|
|
74
|
+
*
|
|
75
|
+
* @param sprintResult - Parsed sprint with tasks
|
|
76
|
+
* @param client - GraphApiClient instance (optional, will create if not provided)
|
|
77
|
+
* @param options - Sync options
|
|
78
|
+
* @returns TaskSyncResponse
|
|
79
|
+
*/
|
|
80
|
+
export async function syncSprintTasksToGraph(sprintResult, client, options = {}) {
|
|
81
|
+
// Check if graph is initialized
|
|
82
|
+
if (!await isGraphInitialized()) {
|
|
83
|
+
throw new Error('Graph not initialized. Run "ginko graph init" first.');
|
|
84
|
+
}
|
|
85
|
+
// Load config to get graphId
|
|
86
|
+
const config = await loadGraphConfig();
|
|
87
|
+
if (!config) {
|
|
88
|
+
throw new Error('Failed to load graph configuration');
|
|
89
|
+
}
|
|
90
|
+
// Create client if not provided
|
|
91
|
+
const apiClient = client || new GraphApiClient(config.apiEndpoint);
|
|
92
|
+
return syncTasksToGraph(sprintResult.tasks, config.graphId, apiClient, options);
|
|
93
|
+
}
|
|
94
|
+
/**
|
|
95
|
+
* Sync multiple sprints' tasks to graph
|
|
96
|
+
*
|
|
97
|
+
* @param sprintResults - Array of parsed sprints with tasks
|
|
98
|
+
* @param options - Sync options
|
|
99
|
+
* @returns BatchSyncResult
|
|
100
|
+
*/
|
|
101
|
+
export async function syncAllSprintTasksToGraph(sprintResults, options = {}) {
|
|
102
|
+
// Check if graph is initialized
|
|
103
|
+
if (!await isGraphInitialized()) {
|
|
104
|
+
return {
|
|
105
|
+
success: false,
|
|
106
|
+
totalTasks: 0,
|
|
107
|
+
created: 0,
|
|
108
|
+
updated: 0,
|
|
109
|
+
relationships: 0,
|
|
110
|
+
errors: ['Graph not initialized. Run "ginko graph init" first.'],
|
|
111
|
+
};
|
|
112
|
+
}
|
|
113
|
+
// Load config
|
|
114
|
+
const config = await loadGraphConfig();
|
|
115
|
+
if (!config) {
|
|
116
|
+
return {
|
|
117
|
+
success: false,
|
|
118
|
+
totalTasks: 0,
|
|
119
|
+
created: 0,
|
|
120
|
+
updated: 0,
|
|
121
|
+
relationships: 0,
|
|
122
|
+
errors: ['Failed to load graph configuration'],
|
|
123
|
+
};
|
|
124
|
+
}
|
|
125
|
+
// Collect all tasks
|
|
126
|
+
const allTasks = [];
|
|
127
|
+
for (const result of sprintResults) {
|
|
128
|
+
allTasks.push(...result.tasks);
|
|
129
|
+
}
|
|
130
|
+
if (allTasks.length === 0) {
|
|
131
|
+
return {
|
|
132
|
+
success: true,
|
|
133
|
+
totalTasks: 0,
|
|
134
|
+
created: 0,
|
|
135
|
+
updated: 0,
|
|
136
|
+
relationships: 0,
|
|
137
|
+
errors: [],
|
|
138
|
+
};
|
|
139
|
+
}
|
|
140
|
+
// Create client
|
|
141
|
+
const client = new GraphApiClient(config.apiEndpoint);
|
|
142
|
+
const errors = [];
|
|
143
|
+
try {
|
|
144
|
+
const response = await syncTasksToGraph(allTasks, config.graphId, client, options);
|
|
145
|
+
return {
|
|
146
|
+
success: true,
|
|
147
|
+
totalTasks: allTasks.length,
|
|
148
|
+
created: response.created,
|
|
149
|
+
updated: response.updated,
|
|
150
|
+
relationships: response.relationships,
|
|
151
|
+
errors,
|
|
152
|
+
};
|
|
153
|
+
}
|
|
154
|
+
catch (error) {
|
|
155
|
+
errors.push(error instanceof Error ? error.message : 'Unknown error during sync');
|
|
156
|
+
return {
|
|
157
|
+
success: false,
|
|
158
|
+
totalTasks: allTasks.length,
|
|
159
|
+
created: 0,
|
|
160
|
+
updated: 0,
|
|
161
|
+
relationships: 0,
|
|
162
|
+
errors,
|
|
163
|
+
};
|
|
164
|
+
}
|
|
165
|
+
}
|
|
166
|
+
/**
|
|
167
|
+
* Get task sync status from graph
|
|
168
|
+
*
|
|
169
|
+
* @param graphId - Graph namespace ID
|
|
170
|
+
* @param sprintId - Optional sprint ID filter
|
|
171
|
+
* @param epicId - Optional epic ID filter
|
|
172
|
+
* @param client - GraphApiClient instance
|
|
173
|
+
* @returns Array of task status objects
|
|
174
|
+
*/
|
|
175
|
+
export async function getTasksFromGraph(graphId, client, filters) {
|
|
176
|
+
return client.getTasks(graphId, filters);
|
|
177
|
+
}
|
|
178
|
+
//# sourceMappingURL=task-graph-sync.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"task-graph-sync.js","sourceRoot":"","sources":["../../src/lib/task-graph-sync.ts"],"names":[],"mappings":"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"}
|