@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.
Files changed (149) hide show
  1. package/dist/commands/epic/index.d.ts +29 -0
  2. package/dist/commands/epic/index.d.ts.map +1 -0
  3. package/dist/commands/epic/index.js +94 -0
  4. package/dist/commands/epic/index.js.map +1 -0
  5. package/dist/commands/epic/status.d.ts +40 -0
  6. package/dist/commands/epic/status.d.ts.map +1 -0
  7. package/dist/commands/epic/status.js +244 -0
  8. package/dist/commands/epic/status.js.map +1 -0
  9. package/dist/commands/graph/api-client.d.ts +221 -1
  10. package/dist/commands/graph/api-client.d.ts.map +1 -1
  11. package/dist/commands/graph/api-client.js +141 -2
  12. package/dist/commands/graph/api-client.js.map +1 -1
  13. package/dist/commands/graph/load.d.ts.map +1 -1
  14. package/dist/commands/graph/load.js +40 -2
  15. package/dist/commands/graph/load.js.map +1 -1
  16. package/dist/commands/handoff.d.ts +3 -3
  17. package/dist/commands/handoff.d.ts.map +1 -1
  18. package/dist/commands/handoff.js +32 -3
  19. package/dist/commands/handoff.js.map +1 -1
  20. package/dist/commands/migrate/index.d.ts +27 -0
  21. package/dist/commands/migrate/index.d.ts.map +1 -0
  22. package/dist/commands/migrate/index.js +76 -0
  23. package/dist/commands/migrate/index.js.map +1 -0
  24. package/dist/commands/migrate/status-migration.d.ts +58 -0
  25. package/dist/commands/migrate/status-migration.d.ts.map +1 -0
  26. package/dist/commands/migrate/status-migration.js +323 -0
  27. package/dist/commands/migrate/status-migration.js.map +1 -0
  28. package/dist/commands/nudging/index.d.ts +24 -0
  29. package/dist/commands/nudging/index.d.ts.map +1 -0
  30. package/dist/commands/nudging/index.js +175 -0
  31. package/dist/commands/nudging/index.js.map +1 -0
  32. package/dist/commands/sprint/create.d.ts +26 -0
  33. package/dist/commands/sprint/create.d.ts.map +1 -0
  34. package/dist/commands/sprint/create.js +269 -0
  35. package/dist/commands/sprint/create.js.map +1 -0
  36. package/dist/commands/sprint/index.d.ts.map +1 -1
  37. package/dist/commands/sprint/index.js +28 -0
  38. package/dist/commands/sprint/index.js.map +1 -1
  39. package/dist/commands/sprint/quick-fix.d.ts +25 -0
  40. package/dist/commands/sprint/quick-fix.d.ts.map +1 -0
  41. package/dist/commands/sprint/quick-fix.js +151 -0
  42. package/dist/commands/sprint/quick-fix.js.map +1 -0
  43. package/dist/commands/sprint/sprint-pipeline-enhanced.d.ts.map +1 -1
  44. package/dist/commands/sprint/sprint-pipeline-enhanced.js +37 -0
  45. package/dist/commands/sprint/sprint-pipeline-enhanced.js.map +1 -1
  46. package/dist/commands/sprint/status.d.ts +42 -0
  47. package/dist/commands/sprint/status.d.ts.map +1 -0
  48. package/dist/commands/sprint/status.js +298 -0
  49. package/dist/commands/sprint/status.js.map +1 -0
  50. package/dist/commands/start/start-reflection.d.ts +53 -0
  51. package/dist/commands/start/start-reflection.d.ts.map +1 -1
  52. package/dist/commands/start/start-reflection.js +464 -71
  53. package/dist/commands/start/start-reflection.js.map +1 -1
  54. package/dist/commands/sync/sprint-syncer.d.ts +19 -12
  55. package/dist/commands/sync/sprint-syncer.d.ts.map +1 -1
  56. package/dist/commands/sync/sprint-syncer.js +58 -140
  57. package/dist/commands/sync/sprint-syncer.js.map +1 -1
  58. package/dist/commands/sync/sync-command.d.ts.map +1 -1
  59. package/dist/commands/sync/sync-command.js +6 -18
  60. package/dist/commands/sync/sync-command.js.map +1 -1
  61. package/dist/commands/task/index.d.ts +25 -0
  62. package/dist/commands/task/index.d.ts.map +1 -0
  63. package/dist/commands/task/index.js +100 -0
  64. package/dist/commands/task/index.js.map +1 -0
  65. package/dist/commands/task/status.d.ts +46 -0
  66. package/dist/commands/task/status.d.ts.map +1 -0
  67. package/dist/commands/task/status.js +348 -0
  68. package/dist/commands/task/status.js.map +1 -0
  69. package/dist/commands/team/index.d.ts +5 -0
  70. package/dist/commands/team/index.d.ts.map +1 -1
  71. package/dist/commands/team/index.js +28 -0
  72. package/dist/commands/team/index.js.map +1 -1
  73. package/dist/commands/team/status.d.ts +16 -0
  74. package/dist/commands/team/status.d.ts.map +1 -0
  75. package/dist/commands/team/status.js +180 -0
  76. package/dist/commands/team/status.js.map +1 -0
  77. package/dist/index.js +21 -32
  78. package/dist/index.js.map +1 -1
  79. package/dist/lib/adoption-score.d.ts +69 -0
  80. package/dist/lib/adoption-score.d.ts.map +1 -0
  81. package/dist/lib/adoption-score.js +206 -0
  82. package/dist/lib/adoption-score.js.map +1 -0
  83. package/dist/lib/coaching-level.d.ts +127 -0
  84. package/dist/lib/coaching-level.d.ts.map +1 -0
  85. package/dist/lib/coaching-level.js +406 -0
  86. package/dist/lib/coaching-level.js.map +1 -0
  87. package/dist/lib/context-loader-events.d.ts.map +1 -1
  88. package/dist/lib/context-loader-events.js +7 -26
  89. package/dist/lib/context-loader-events.js.map +1 -1
  90. package/dist/lib/event-logger.d.ts +42 -0
  91. package/dist/lib/event-logger.d.ts.map +1 -1
  92. package/dist/lib/event-logger.js +77 -0
  93. package/dist/lib/event-logger.js.map +1 -1
  94. package/dist/lib/output-formatter.d.ts +8 -2
  95. package/dist/lib/output-formatter.d.ts.map +1 -1
  96. package/dist/lib/output-formatter.js +98 -18
  97. package/dist/lib/output-formatter.js.map +1 -1
  98. package/dist/lib/pending-updates.d.ts +148 -0
  99. package/dist/lib/pending-updates.d.ts.map +1 -0
  100. package/dist/lib/pending-updates.js +301 -0
  101. package/dist/lib/pending-updates.js.map +1 -0
  102. package/dist/lib/planning-menu.d.ts +69 -0
  103. package/dist/lib/planning-menu.d.ts.map +1 -0
  104. package/dist/lib/planning-menu.js +342 -0
  105. package/dist/lib/planning-menu.js.map +1 -0
  106. package/dist/lib/sprint-loader.d.ts +86 -14
  107. package/dist/lib/sprint-loader.d.ts.map +1 -1
  108. package/dist/lib/sprint-loader.js +293 -98
  109. package/dist/lib/sprint-loader.js.map +1 -1
  110. package/dist/lib/state-cache.d.ts +142 -0
  111. package/dist/lib/state-cache.d.ts.map +1 -0
  112. package/dist/lib/state-cache.js +259 -0
  113. package/dist/lib/state-cache.js.map +1 -0
  114. package/dist/lib/targeted-coaching.d.ts +71 -0
  115. package/dist/lib/targeted-coaching.d.ts.map +1 -0
  116. package/dist/lib/targeted-coaching.js +318 -0
  117. package/dist/lib/targeted-coaching.js.map +1 -0
  118. package/dist/lib/task-graph-sync.d.ts +105 -0
  119. package/dist/lib/task-graph-sync.d.ts.map +1 -0
  120. package/dist/lib/task-graph-sync.js +178 -0
  121. package/dist/lib/task-graph-sync.js.map +1 -0
  122. package/dist/lib/task-parser.d.ts +109 -0
  123. package/dist/lib/task-parser.d.ts.map +1 -0
  124. package/dist/lib/task-parser.js +407 -0
  125. package/dist/lib/task-parser.js.map +1 -0
  126. package/dist/lib/user-sprint.d.ts +53 -0
  127. package/dist/lib/user-sprint.d.ts.map +1 -1
  128. package/dist/lib/user-sprint.js +137 -2
  129. package/dist/lib/user-sprint.js.map +1 -1
  130. package/dist/lib/work-reconciliation.d.ts +59 -0
  131. package/dist/lib/work-reconciliation.d.ts.map +1 -0
  132. package/dist/lib/work-reconciliation.js +267 -0
  133. package/dist/lib/work-reconciliation.js.map +1 -0
  134. package/dist/templates/ai-instructions-template.d.ts.map +1 -1
  135. package/dist/templates/ai-instructions-template.js +7 -5
  136. package/dist/templates/ai-instructions-template.js.map +1 -1
  137. package/dist/templates/epic-template.md +0 -2
  138. package/dist/types/config.d.ts.map +1 -1
  139. package/dist/types/config.js +7 -5
  140. package/dist/types/config.js.map +1 -1
  141. package/dist/utils/synthesis.d.ts +4 -0
  142. package/dist/utils/synthesis.d.ts.map +1 -1
  143. package/dist/utils/synthesis.js +12 -18
  144. package/dist/utils/synthesis.js.map +1 -1
  145. package/dist/utils/version-check.d.ts +26 -0
  146. package/dist/utils/version-check.d.ts.map +1 -0
  147. package/dist/utils/version-check.js +186 -0
  148. package/dist/utils/version-check.js.map +1 -0
  149. package/package.json +2 -2
@@ -0,0 +1,142 @@
1
+ /**
2
+ * @fileType: utility
3
+ * @status: current
4
+ * @updated: 2026-01-19
5
+ * @tags: [cache, offline, state, EPIC-015]
6
+ * @related: [staleness-detector.ts, user-sprint.ts, start-reflection.ts]
7
+ * @priority: high
8
+ * @complexity: medium
9
+ * @dependencies: [fs-extra, path]
10
+ */
11
+ /**
12
+ * Data about the active sprint for display
13
+ */
14
+ export interface ActiveSprintData {
15
+ sprintId: string;
16
+ sprintName: string;
17
+ epicId: string;
18
+ epicName?: string;
19
+ progress: {
20
+ completed: number;
21
+ total: number;
22
+ percentage: number;
23
+ };
24
+ currentTask?: {
25
+ taskId: string;
26
+ taskName: string;
27
+ status: 'pending' | 'in_progress' | 'completed';
28
+ };
29
+ nextTask?: {
30
+ taskId: string;
31
+ taskName: string;
32
+ };
33
+ }
34
+ /**
35
+ * Cached state structure
36
+ */
37
+ export interface StateCache {
38
+ version: 1;
39
+ fetched_at: string;
40
+ graph_id: string;
41
+ active_sprint: ActiveSprintData;
42
+ }
43
+ /**
44
+ * Result of checking cache staleness
45
+ */
46
+ export interface CacheStalenessResult {
47
+ level: 'fresh' | 'stale' | 'expired';
48
+ age: number;
49
+ ageHuman: string;
50
+ isFresh: boolean;
51
+ showWarning: boolean;
52
+ }
53
+ /**
54
+ * Load cached state from disk
55
+ *
56
+ * @returns StateCache if valid cache exists, null otherwise
57
+ *
58
+ * @example
59
+ * ```typescript
60
+ * const cache = await loadStateCache();
61
+ * if (cache) {
62
+ * console.log(`Sprint: ${cache.active_sprint.sprintName}`);
63
+ * }
64
+ * ```
65
+ */
66
+ export declare function loadStateCache(): Promise<StateCache | null>;
67
+ /**
68
+ * Save state data to cache
69
+ * Uses atomic write (temp file + rename) to prevent partial writes
70
+ *
71
+ * @param data - Active sprint data to cache
72
+ * @param graphId - The graph ID this data belongs to
73
+ *
74
+ * @example
75
+ * ```typescript
76
+ * await saveStateCache(sprintData, 'graph-123');
77
+ * ```
78
+ */
79
+ export declare function saveStateCache(data: ActiveSprintData, graphId: string): Promise<void>;
80
+ /**
81
+ * Clear the state cache
82
+ * Called when cache should be invalidated (e.g., logout, graph switch)
83
+ *
84
+ * @example
85
+ * ```typescript
86
+ * await clearStateCache();
87
+ * ```
88
+ */
89
+ export declare function clearStateCache(): Promise<void>;
90
+ /**
91
+ * Check staleness of cached state
92
+ *
93
+ * Staleness levels:
94
+ * - fresh: < 5 minutes old
95
+ * - stale: 5 minutes to 24 hours old
96
+ * - expired: > 24 hours old
97
+ *
98
+ * @param cache - The cached state to check
99
+ * @returns Staleness result with level, age, and display info
100
+ *
101
+ * @example
102
+ * ```typescript
103
+ * const cache = await loadStateCache();
104
+ * if (cache) {
105
+ * const staleness = checkCacheStaleness(cache);
106
+ * if (staleness.showWarning) {
107
+ * console.log(`Cache is ${staleness.level}: ${staleness.ageHuman}`);
108
+ * }
109
+ * }
110
+ * ```
111
+ */
112
+ export declare function checkCacheStaleness(cache: StateCache): CacheStalenessResult;
113
+ /**
114
+ * Format cache age for human-readable display
115
+ *
116
+ * @param fetchedAt - ISO timestamp string
117
+ * @returns Human-readable age string (e.g., "15 min ago", "2 hours ago")
118
+ *
119
+ * @example
120
+ * ```typescript
121
+ * const age = formatCacheAge('2026-01-19T10:00:00.000Z');
122
+ * // Returns something like "15 min ago"
123
+ * ```
124
+ */
125
+ export declare function formatCacheAge(fetchedAt: string): string;
126
+ /**
127
+ * Get the full path to the cache file
128
+ */
129
+ declare function getCachePath(): Promise<string>;
130
+ /**
131
+ * Validate that cache data has correct structure and version
132
+ */
133
+ declare function isValidCache(data: unknown): data is StateCache;
134
+ export declare const _internal: {
135
+ getCachePath: typeof getCachePath;
136
+ isValidCache: typeof isValidCache;
137
+ FRESH_THRESHOLD_MS: number;
138
+ EXPIRED_THRESHOLD_MS: number;
139
+ CACHE_VERSION: number;
140
+ };
141
+ export {};
142
+ //# sourceMappingURL=state-cache.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"state-cache.d.ts","sourceRoot":"","sources":["../../src/lib/state-cache.ts"],"names":[],"mappings":"AAAA;;;;;;;;;GASG;AAsBH;;GAEG;AACH,MAAM,WAAW,gBAAgB;IAC/B,QAAQ,EAAE,MAAM,CAAC;IACjB,UAAU,EAAE,MAAM,CAAC;IACnB,MAAM,EAAE,MAAM,CAAC;IACf,QAAQ,CAAC,EAAE,MAAM,CAAC;IAClB,QAAQ,EAAE;QACR,SAAS,EAAE,MAAM,CAAC;QAClB,KAAK,EAAE,MAAM,CAAC;QACd,UAAU,EAAE,MAAM,CAAC;KACpB,CAAC;IACF,WAAW,CAAC,EAAE;QACZ,MAAM,EAAE,MAAM,CAAC;QACf,QAAQ,EAAE,MAAM,CAAC;QACjB,MAAM,EAAE,SAAS,GAAG,aAAa,GAAG,WAAW,CAAC;KACjD,CAAC;IACF,QAAQ,CAAC,EAAE;QACT,MAAM,EAAE,MAAM,CAAC;QACf,QAAQ,EAAE,MAAM,CAAC;KAClB,CAAC;CACH;AAED;;GAEG;AACH,MAAM,WAAW,UAAU;IACzB,OAAO,EAAE,CAAC,CAAC;IACX,UAAU,EAAE,MAAM,CAAC;IACnB,QAAQ,EAAE,MAAM,CAAC;IACjB,aAAa,EAAE,gBAAgB,CAAC;CACjC;AAED;;GAEG;AACH,MAAM,WAAW,oBAAoB;IACnC,KAAK,EAAE,OAAO,GAAG,OAAO,GAAG,SAAS,CAAC;IACrC,GAAG,EAAE,MAAM,CAAC;IACZ,QAAQ,EAAE,MAAM,CAAC;IACjB,OAAO,EAAE,OAAO,CAAC;IACjB,WAAW,EAAE,OAAO,CAAC;CACtB;AAiBD;;;;;;;;;;;;GAYG;AACH,wBAAsB,cAAc,IAAI,OAAO,CAAC,UAAU,GAAG,IAAI,CAAC,CAoBjE;AAED;;;;;;;;;;;GAWG;AACH,wBAAsB,cAAc,CAClC,IAAI,EAAE,gBAAgB,EACtB,OAAO,EAAE,MAAM,GACd,OAAO,CAAC,IAAI,CAAC,CA4Bf;AAED;;;;;;;;GAQG;AACH,wBAAsB,eAAe,IAAI,OAAO,CAAC,IAAI,CAAC,CAUrD;AAED;;;;;;;;;;;;;;;;;;;;;GAqBG;AACH,wBAAgB,mBAAmB,CAAC,KAAK,EAAE,UAAU,GAAG,oBAAoB,CAsB3E;AAED;;;;;;;;;;;GAWG;AACH,wBAAgB,cAAc,CAAC,SAAS,EAAE,MAAM,GAAG,MAAM,CAwBxD;AAMD;;GAEG;AACH,iBAAe,YAAY,IAAI,OAAO,CAAC,MAAM,CAAC,CAG7C;AAED;;GAEG;AACH,iBAAS,YAAY,CAAC,IAAI,EAAE,OAAO,GAAG,IAAI,IAAI,UAAU,CAsCvD;AAMD,eAAO,MAAM,SAAS;;;;;;CAMrB,CAAC"}
@@ -0,0 +1,259 @@
1
+ /**
2
+ * @fileType: utility
3
+ * @status: current
4
+ * @updated: 2026-01-19
5
+ * @tags: [cache, offline, state, EPIC-015]
6
+ * @related: [staleness-detector.ts, user-sprint.ts, start-reflection.ts]
7
+ * @priority: high
8
+ * @complexity: medium
9
+ * @dependencies: [fs-extra, path]
10
+ */
11
+ /**
12
+ * Local State Cache (EPIC-015 Sprint 2)
13
+ *
14
+ * Provides local caching for API state data to enable:
15
+ * - Offline operation when API is unavailable
16
+ * - Faster startup by avoiding API calls for fresh data
17
+ * - Graceful degradation with staleness indicators
18
+ *
19
+ * Cache location: .ginko/state-cache.json
20
+ * Uses atomic writes (temp file + rename) to prevent partial writes.
21
+ */
22
+ import fs from 'fs-extra';
23
+ import path from 'path';
24
+ import { getGinkoDir } from '../utils/helpers.js';
25
+ // =============================================================================
26
+ // Constants
27
+ // =============================================================================
28
+ const CACHE_FILE = 'state-cache.json';
29
+ const CACHE_VERSION = 1;
30
+ // Staleness thresholds in milliseconds
31
+ const FRESH_THRESHOLD_MS = 5 * 60 * 1000; // 5 minutes
32
+ const EXPIRED_THRESHOLD_MS = 24 * 60 * 60 * 1000; // 24 hours
33
+ // =============================================================================
34
+ // Main API
35
+ // =============================================================================
36
+ /**
37
+ * Load cached state from disk
38
+ *
39
+ * @returns StateCache if valid cache exists, null otherwise
40
+ *
41
+ * @example
42
+ * ```typescript
43
+ * const cache = await loadStateCache();
44
+ * if (cache) {
45
+ * console.log(`Sprint: ${cache.active_sprint.sprintName}`);
46
+ * }
47
+ * ```
48
+ */
49
+ export async function loadStateCache() {
50
+ try {
51
+ const cachePath = await getCachePath();
52
+ if (!await fs.pathExists(cachePath)) {
53
+ return null;
54
+ }
55
+ const data = await fs.readJSON(cachePath);
56
+ // Validate cache version and required fields
57
+ if (!isValidCache(data)) {
58
+ return null;
59
+ }
60
+ return data;
61
+ }
62
+ catch (error) {
63
+ // File doesn't exist, is invalid JSON, or other read error
64
+ return null;
65
+ }
66
+ }
67
+ /**
68
+ * Save state data to cache
69
+ * Uses atomic write (temp file + rename) to prevent partial writes
70
+ *
71
+ * @param data - Active sprint data to cache
72
+ * @param graphId - The graph ID this data belongs to
73
+ *
74
+ * @example
75
+ * ```typescript
76
+ * await saveStateCache(sprintData, 'graph-123');
77
+ * ```
78
+ */
79
+ export async function saveStateCache(data, graphId) {
80
+ const cachePath = await getCachePath();
81
+ const cacheDir = path.dirname(cachePath);
82
+ const tempPath = `${cachePath}.tmp.${Date.now()}`;
83
+ // Ensure .ginko directory exists
84
+ await fs.ensureDir(cacheDir);
85
+ const cache = {
86
+ version: CACHE_VERSION,
87
+ fetched_at: new Date().toISOString(),
88
+ graph_id: graphId,
89
+ active_sprint: data,
90
+ };
91
+ // Atomic write: write to temp file, then rename
92
+ try {
93
+ await fs.writeJSON(tempPath, cache, { spaces: 2 });
94
+ await fs.rename(tempPath, cachePath);
95
+ }
96
+ catch (error) {
97
+ // Clean up temp file if rename failed
98
+ try {
99
+ await fs.remove(tempPath);
100
+ }
101
+ catch {
102
+ // Ignore cleanup errors
103
+ }
104
+ throw error;
105
+ }
106
+ }
107
+ /**
108
+ * Clear the state cache
109
+ * Called when cache should be invalidated (e.g., logout, graph switch)
110
+ *
111
+ * @example
112
+ * ```typescript
113
+ * await clearStateCache();
114
+ * ```
115
+ */
116
+ export async function clearStateCache() {
117
+ try {
118
+ const cachePath = await getCachePath();
119
+ if (await fs.pathExists(cachePath)) {
120
+ await fs.remove(cachePath);
121
+ }
122
+ }
123
+ catch (error) {
124
+ // Ignore errors when clearing cache
125
+ }
126
+ }
127
+ /**
128
+ * Check staleness of cached state
129
+ *
130
+ * Staleness levels:
131
+ * - fresh: < 5 minutes old
132
+ * - stale: 5 minutes to 24 hours old
133
+ * - expired: > 24 hours old
134
+ *
135
+ * @param cache - The cached state to check
136
+ * @returns Staleness result with level, age, and display info
137
+ *
138
+ * @example
139
+ * ```typescript
140
+ * const cache = await loadStateCache();
141
+ * if (cache) {
142
+ * const staleness = checkCacheStaleness(cache);
143
+ * if (staleness.showWarning) {
144
+ * console.log(`Cache is ${staleness.level}: ${staleness.ageHuman}`);
145
+ * }
146
+ * }
147
+ * ```
148
+ */
149
+ export function checkCacheStaleness(cache) {
150
+ const fetchedAt = new Date(cache.fetched_at);
151
+ const now = new Date();
152
+ const ageMs = now.getTime() - fetchedAt.getTime();
153
+ let level;
154
+ if (ageMs < FRESH_THRESHOLD_MS) {
155
+ level = 'fresh';
156
+ }
157
+ else if (ageMs < EXPIRED_THRESHOLD_MS) {
158
+ level = 'stale';
159
+ }
160
+ else {
161
+ level = 'expired';
162
+ }
163
+ return {
164
+ level,
165
+ age: ageMs,
166
+ ageHuman: formatCacheAge(cache.fetched_at),
167
+ isFresh: level === 'fresh',
168
+ showWarning: level !== 'fresh',
169
+ };
170
+ }
171
+ /**
172
+ * Format cache age for human-readable display
173
+ *
174
+ * @param fetchedAt - ISO timestamp string
175
+ * @returns Human-readable age string (e.g., "15 min ago", "2 hours ago")
176
+ *
177
+ * @example
178
+ * ```typescript
179
+ * const age = formatCacheAge('2026-01-19T10:00:00.000Z');
180
+ * // Returns something like "15 min ago"
181
+ * ```
182
+ */
183
+ export function formatCacheAge(fetchedAt) {
184
+ const date = new Date(fetchedAt);
185
+ const now = new Date();
186
+ const diffMs = now.getTime() - date.getTime();
187
+ const diffSecs = Math.floor(diffMs / 1000);
188
+ const diffMins = Math.floor(diffMs / (1000 * 60));
189
+ const diffHours = Math.floor(diffMs / (1000 * 60 * 60));
190
+ const diffDays = Math.floor(diffMs / (1000 * 60 * 60 * 24));
191
+ if (diffSecs < 60) {
192
+ return 'just now';
193
+ }
194
+ if (diffMins < 60) {
195
+ return `${diffMins} min ago`;
196
+ }
197
+ if (diffHours < 24) {
198
+ return `${diffHours} hour${diffHours === 1 ? '' : 's'} ago`;
199
+ }
200
+ if (diffDays < 7) {
201
+ return `${diffDays} day${diffDays === 1 ? '' : 's'} ago`;
202
+ }
203
+ return date.toLocaleDateString();
204
+ }
205
+ // =============================================================================
206
+ // Helper Functions
207
+ // =============================================================================
208
+ /**
209
+ * Get the full path to the cache file
210
+ */
211
+ async function getCachePath() {
212
+ const ginkoDir = await getGinkoDir();
213
+ return path.join(ginkoDir, CACHE_FILE);
214
+ }
215
+ /**
216
+ * Validate that cache data has correct structure and version
217
+ */
218
+ function isValidCache(data) {
219
+ if (!data || typeof data !== 'object') {
220
+ return false;
221
+ }
222
+ const cache = data;
223
+ // Check version
224
+ if (cache.version !== CACHE_VERSION) {
225
+ return false;
226
+ }
227
+ // Check required fields
228
+ if (!cache.fetched_at || typeof cache.fetched_at !== 'string') {
229
+ return false;
230
+ }
231
+ if (!cache.graph_id || typeof cache.graph_id !== 'string') {
232
+ return false;
233
+ }
234
+ if (!cache.active_sprint || typeof cache.active_sprint !== 'object') {
235
+ return false;
236
+ }
237
+ // Validate active_sprint structure
238
+ const sprint = cache.active_sprint;
239
+ if (!sprint.sprintId || !sprint.sprintName || !sprint.epicId) {
240
+ return false;
241
+ }
242
+ if (!sprint.progress || typeof sprint.progress.completed !== 'number' ||
243
+ typeof sprint.progress.total !== 'number' ||
244
+ typeof sprint.progress.percentage !== 'number') {
245
+ return false;
246
+ }
247
+ return true;
248
+ }
249
+ // =============================================================================
250
+ // Exports for Testing
251
+ // =============================================================================
252
+ export const _internal = {
253
+ getCachePath,
254
+ isValidCache,
255
+ FRESH_THRESHOLD_MS,
256
+ EXPIRED_THRESHOLD_MS,
257
+ CACHE_VERSION,
258
+ };
259
+ //# sourceMappingURL=state-cache.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"state-cache.js","sourceRoot":"","sources":["../../src/lib/state-cache.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,71 @@
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
+ import { CoachingContext } from './coaching-level.js';
12
+ export type MetricType = 'sessionEfficiency' | 'patternAdoption' | 'collaborationQuality' | 'antiPatterns';
13
+ export type CoachingContext_Type = 'start' | 'handoff' | 'task_complete' | 'planning';
14
+ export interface CoachingTip {
15
+ id: string;
16
+ metric: MetricType;
17
+ context: CoachingContext_Type[];
18
+ message: string;
19
+ action?: string;
20
+ priority: number;
21
+ }
22
+ export interface ShownTipsRecord {
23
+ sessionId: string;
24
+ shownTipIds: string[];
25
+ lastUpdated: string;
26
+ }
27
+ /**
28
+ * All available coaching tips organized by metric
29
+ */
30
+ export declare const COACHING_TIPS: CoachingTip[];
31
+ declare function loadShownTips(): Promise<ShownTipsRecord>;
32
+ declare function saveShownTips(record: ShownTipsRecord): Promise<void>;
33
+ declare function markTipAsShown(tipId: string): Promise<void>;
34
+ declare function isTipShown(tipId: string): Promise<boolean>;
35
+ /**
36
+ * Get applicable tips for a given context and coaching context
37
+ *
38
+ * @param coachingCtx - Coaching context with metric scores
39
+ * @param context - Current context (start, handoff, etc.)
40
+ * @param limit - Maximum number of tips to return
41
+ * @returns Array of applicable tips, prioritized
42
+ */
43
+ export declare function getApplicableTips(coachingCtx: CoachingContext, context: CoachingContext_Type, limit?: number): Promise<CoachingTip[]>;
44
+ declare function getMetricValue(ctx: CoachingContext, metric: MetricType): number;
45
+ /**
46
+ * Display a coaching tip to the console
47
+ */
48
+ export declare function displayTip(tip: CoachingTip): void;
49
+ /**
50
+ * Show targeted coaching tips for the current context
51
+ *
52
+ * @param coachingCtx - Coaching context with metric scores
53
+ * @param context - Current context
54
+ * @returns Number of tips shown
55
+ */
56
+ export declare function showTargetedCoaching(coachingCtx: CoachingContext, context: CoachingContext_Type): Promise<number>;
57
+ /**
58
+ * Get coaching tip for a specific metric (for inline use)
59
+ */
60
+ export declare function getTipForMetric(coachingCtx: CoachingContext, metric: MetricType, context: CoachingContext_Type): Promise<string | null>;
61
+ export declare const METRIC_DISPLAY_NAMES: Record<MetricType, string>;
62
+ export declare const __testing: {
63
+ LOW_THRESHOLD: number;
64
+ loadShownTips: typeof loadShownTips;
65
+ saveShownTips: typeof saveShownTips;
66
+ markTipAsShown: typeof markTipAsShown;
67
+ isTipShown: typeof isTipShown;
68
+ getMetricValue: typeof getMetricValue;
69
+ };
70
+ export {};
71
+ //# sourceMappingURL=targeted-coaching.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"targeted-coaching.d.ts","sourceRoot":"","sources":["../../src/lib/targeted-coaching.ts"],"names":[],"mappings":"AAAA;;;;;;;;;GASG;AAyBH,OAAO,EAAE,eAAe,EAAe,MAAM,qBAAqB,CAAC;AAOnE,MAAM,MAAM,UAAU,GAAG,mBAAmB,GAAG,iBAAiB,GAAG,sBAAsB,GAAG,cAAc,CAAC;AAC3G,MAAM,MAAM,oBAAoB,GAAG,OAAO,GAAG,SAAS,GAAG,eAAe,GAAG,UAAU,CAAC;AAEtF,MAAM,WAAW,WAAW;IAC1B,EAAE,EAAE,MAAM,CAAC;IACX,MAAM,EAAE,UAAU,CAAC;IACnB,OAAO,EAAE,oBAAoB,EAAE,CAAC;IAChC,OAAO,EAAE,MAAM,CAAC;IAChB,MAAM,CAAC,EAAE,MAAM,CAAC;IAChB,QAAQ,EAAE,MAAM,CAAC;CAClB;AAED,MAAM,WAAW,eAAe;IAC9B,SAAS,EAAE,MAAM,CAAC;IAClB,WAAW,EAAE,MAAM,EAAE,CAAC;IACtB,WAAW,EAAE,MAAM,CAAC;CACrB;AASD;;GAEG;AACH,eAAO,MAAM,aAAa,EAAE,WAAW,EAmGtC,CAAC;AAaF,iBAAe,aAAa,IAAI,OAAO,CAAC,eAAe,CAAC,CA0BvD;AAED,iBAAe,aAAa,CAAC,MAAM,EAAE,eAAe,GAAG,OAAO,CAAC,IAAI,CAAC,CAKnE;AAMD,iBAAe,cAAc,CAAC,KAAK,EAAE,MAAM,GAAG,OAAO,CAAC,IAAI,CAAC,CAM1D;AAED,iBAAe,UAAU,CAAC,KAAK,EAAE,MAAM,GAAG,OAAO,CAAC,OAAO,CAAC,CAGzD;AAMD;;;;;;;GAOG;AACH,wBAAsB,iBAAiB,CACrC,WAAW,EAAE,eAAe,EAC5B,OAAO,EAAE,oBAAoB,EAC7B,KAAK,GAAE,MAAU,GAChB,OAAO,CAAC,WAAW,EAAE,CAAC,CAiCxB;AAED,iBAAS,cAAc,CAAC,GAAG,EAAE,eAAe,EAAE,MAAM,EAAE,UAAU,GAAG,MAAM,CAWxE;AAMD;;GAEG;AACH,wBAAgB,UAAU,CAAC,GAAG,EAAE,WAAW,GAAG,IAAI,CAQjD;AAED;;;;;;GAMG;AACH,wBAAsB,oBAAoB,CACxC,WAAW,EAAE,eAAe,EAC5B,OAAO,EAAE,oBAAoB,GAC5B,OAAO,CAAC,MAAM,CAAC,CAcjB;AAED;;GAEG;AACH,wBAAsB,eAAe,CACnC,WAAW,EAAE,eAAe,EAC5B,MAAM,EAAE,UAAU,EAClB,OAAO,EAAE,oBAAoB,GAC5B,OAAO,CAAC,MAAM,GAAG,IAAI,CAAC,CAIxB;AAmBD,eAAO,MAAM,oBAAoB,EAAE,MAAM,CAAC,UAAU,EAAE,MAAM,CAK3D,CAAC;AAMF,eAAO,MAAM,SAAS;;;;;;;CAOrB,CAAC"}