@ginkoai/cli 2.4.4 → 2.5.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/LICENSE +661 -21
- package/dist/commands/agent/status.d.ts.map +1 -1
- package/dist/commands/agent/status.js +2 -0
- package/dist/commands/agent/status.js.map +1 -1
- package/dist/commands/assign.d.ts.map +1 -1
- package/dist/commands/assign.js +2 -0
- package/dist/commands/assign.js.map +1 -1
- package/dist/commands/charter.js +3 -3
- package/dist/commands/charter.js.map +1 -1
- package/dist/commands/context/index.d.ts +28 -0
- package/dist/commands/context/index.d.ts.map +1 -0
- package/dist/commands/context/index.js +165 -0
- package/dist/commands/context/index.js.map +1 -0
- package/dist/commands/context/score.d.ts +34 -0
- package/dist/commands/context/score.d.ts.map +1 -0
- package/dist/commands/context/score.js +163 -0
- package/dist/commands/context/score.js.map +1 -0
- package/dist/commands/create.d.ts.map +1 -1
- package/dist/commands/create.js +10 -0
- package/dist/commands/create.js.map +1 -1
- package/dist/commands/diff/diff-command.d.ts.map +1 -1
- package/dist/commands/diff/diff-command.js +2 -0
- package/dist/commands/diff/diff-command.js.map +1 -1
- package/dist/commands/epic/status.d.ts.map +1 -1
- package/dist/commands/epic/status.js +5 -0
- package/dist/commands/epic/status.js.map +1 -1
- package/dist/commands/graph/api-client.d.ts +131 -0
- package/dist/commands/graph/api-client.d.ts.map +1 -1
- package/dist/commands/graph/api-client.js +153 -0
- package/dist/commands/graph/api-client.js.map +1 -1
- package/dist/commands/graph/cleanup.d.ts.map +1 -1
- package/dist/commands/graph/cleanup.js +2 -0
- package/dist/commands/graph/cleanup.js.map +1 -1
- package/dist/commands/graph/explore.d.ts.map +1 -1
- package/dist/commands/graph/explore.js +2 -0
- package/dist/commands/graph/explore.js.map +1 -1
- package/dist/commands/graph/init.d.ts.map +1 -1
- package/dist/commands/graph/init.js +4 -10
- package/dist/commands/graph/init.js.map +1 -1
- package/dist/commands/graph/query.d.ts.map +1 -1
- package/dist/commands/graph/query.js +2 -0
- package/dist/commands/graph/query.js.map +1 -1
- package/dist/commands/graph/status.d.ts.map +1 -1
- package/dist/commands/graph/status.js +2 -0
- package/dist/commands/graph/status.js.map +1 -1
- package/dist/commands/handoff.d.ts.map +1 -1
- package/dist/commands/handoff.js +34 -0
- package/dist/commands/handoff.js.map +1 -1
- package/dist/commands/health.d.ts +15 -0
- package/dist/commands/health.d.ts.map +1 -0
- package/dist/commands/health.js +212 -0
- package/dist/commands/health.js.map +1 -0
- package/dist/commands/init-copilot.js +1 -1
- package/dist/commands/init-copilot.js.map +1 -1
- package/dist/commands/init.d.ts.map +1 -1
- package/dist/commands/init.js +74 -2
- package/dist/commands/init.js.map +1 -1
- package/dist/commands/join/index.js +2 -2
- package/dist/commands/knowledge/create.d.ts.map +1 -1
- package/dist/commands/knowledge/create.js +2 -0
- package/dist/commands/knowledge/create.js.map +1 -1
- package/dist/commands/knowledge/graph.d.ts.map +1 -1
- package/dist/commands/knowledge/graph.js +2 -0
- package/dist/commands/knowledge/graph.js.map +1 -1
- package/dist/commands/knowledge/search.d.ts.map +1 -1
- package/dist/commands/knowledge/search.js +2 -0
- package/dist/commands/knowledge/search.js.map +1 -1
- package/dist/commands/log.d.ts.map +1 -1
- package/dist/commands/log.js +4 -3
- package/dist/commands/log.js.map +1 -1
- package/dist/commands/orchestrate.d.ts.map +1 -1
- package/dist/commands/orchestrate.js +2 -0
- package/dist/commands/orchestrate.js.map +1 -1
- package/dist/commands/pull/pull-command.d.ts.map +1 -1
- package/dist/commands/pull/pull-command.js +2 -0
- package/dist/commands/pull/pull-command.js.map +1 -1
- package/dist/commands/push/push-command.d.ts.map +1 -1
- package/dist/commands/push/push-command.js +19 -2
- package/dist/commands/push/push-command.js.map +1 -1
- package/dist/commands/ship.js +1 -1
- package/dist/commands/ship.js.map +1 -1
- package/dist/commands/sprint/create.d.ts +9 -5
- package/dist/commands/sprint/create.d.ts.map +1 -1
- package/dist/commands/sprint/create.js +226 -29
- package/dist/commands/sprint/create.js.map +1 -1
- package/dist/commands/sprint/index.d.ts.map +1 -1
- package/dist/commands/sprint/index.js +9 -5
- package/dist/commands/sprint/index.js.map +1 -1
- package/dist/commands/sprint/status.d.ts +3 -0
- package/dist/commands/sprint/status.d.ts.map +1 -1
- package/dist/commands/sprint/status.js +88 -2
- package/dist/commands/sprint/status.js.map +1 -1
- package/dist/commands/start/index.js +3 -3
- package/dist/commands/start/index.js.map +1 -1
- package/dist/commands/start/start-reflection.d.ts +5 -0
- package/dist/commands/start/start-reflection.d.ts.map +1 -1
- package/dist/commands/start/start-reflection.js +60 -11
- package/dist/commands/start/start-reflection.js.map +1 -1
- package/dist/commands/sync/sync-command.js +1 -1
- package/dist/commands/sync/sync-command.js.map +1 -1
- package/dist/commands/sync/team-sync.js +1 -1
- package/dist/commands/task/status.d.ts +1 -1
- package/dist/commands/task/status.d.ts.map +1 -1
- package/dist/commands/task/status.js +161 -6
- package/dist/commands/task/status.js.map +1 -1
- package/dist/commands/team/members.d.ts.map +1 -1
- package/dist/commands/team/members.js +4 -0
- package/dist/commands/team/members.js.map +1 -1
- package/dist/commands/team/projects.d.ts.map +1 -1
- package/dist/commands/team/projects.js +3 -0
- package/dist/commands/team/projects.js.map +1 -1
- package/dist/commands/team/status.d.ts.map +1 -1
- package/dist/commands/team/status.js +2 -0
- package/dist/commands/team/status.js.map +1 -1
- package/dist/index.js +12 -8
- package/dist/index.js.map +1 -1
- package/dist/lib/adoption-score.d.ts +1 -1
- package/dist/lib/adoption-score.d.ts.map +1 -1
- package/dist/lib/adoption-score.js +1 -0
- package/dist/lib/adoption-score.js.map +1 -1
- package/dist/lib/context-loader-events.d.ts +4 -4
- package/dist/lib/context-loader-events.d.ts.map +1 -1
- package/dist/lib/context-loader-events.js +69 -18
- package/dist/lib/context-loader-events.js.map +1 -1
- package/dist/lib/context-quality.d.ts +224 -0
- package/dist/lib/context-quality.d.ts.map +1 -0
- package/dist/lib/context-quality.js +363 -0
- package/dist/lib/context-quality.js.map +1 -0
- package/dist/lib/event-logger.d.ts.map +1 -1
- package/dist/lib/event-logger.js +2 -3
- package/dist/lib/event-logger.js.map +1 -1
- package/dist/lib/health-checker.d.ts +35 -0
- package/dist/lib/health-checker.d.ts.map +1 -0
- package/dist/lib/health-checker.js +475 -0
- package/dist/lib/health-checker.js.map +1 -0
- package/dist/lib/output-formatter.d.ts +48 -0
- package/dist/lib/output-formatter.d.ts.map +1 -1
- package/dist/lib/output-formatter.js +168 -4
- package/dist/lib/output-formatter.js.map +1 -1
- package/dist/lib/resumption-brief.d.ts +91 -0
- package/dist/lib/resumption-brief.d.ts.map +1 -0
- package/dist/lib/resumption-brief.js +344 -0
- package/dist/lib/resumption-brief.js.map +1 -0
- package/dist/lib/staleness-detector.js +1 -1
- package/dist/lib/state-cache.d.ts +43 -0
- package/dist/lib/state-cache.d.ts.map +1 -1
- package/dist/lib/state-cache.js +72 -0
- package/dist/lib/state-cache.js.map +1 -1
- package/dist/lib/targeted-coaching.js +2 -2
- package/dist/lib/task-parser.d.ts +34 -4
- package/dist/lib/task-parser.d.ts.map +1 -1
- package/dist/lib/task-parser.js +110 -4
- package/dist/lib/task-parser.js.map +1 -1
- package/dist/services/context-search.d.ts.map +1 -1
- package/dist/services/context-search.js +4 -2
- package/dist/services/context-search.js.map +1 -1
- package/dist/templates/ai-instructions-template.d.ts.map +1 -1
- package/dist/templates/ai-instructions-template.js +20 -0
- package/dist/templates/ai-instructions-template.js.map +1 -1
- package/dist/templates/commands/handoff.md +40 -0
- package/dist/templates/commands/quick.md +27 -0
- package/dist/templates/commands/ship.md +43 -0
- package/dist/templates/commands/start.md +15 -0
- package/dist/templates/commands/vibecheck.md +36 -0
- package/dist/templates/skills/ginko/SKILL.md +1 -8
- package/dist/templates/sprint-template.md +273 -0
- package/dist/utils/cloud-guard.d.ts +48 -0
- package/dist/utils/cloud-guard.d.ts.map +1 -0
- package/dist/utils/cloud-guard.js +107 -0
- package/dist/utils/cloud-guard.js.map +1 -0
- package/dist/utils/config-loader.d.ts +2 -2
- package/dist/utils/config-loader.js +2 -2
- package/dist/utils/helpers.d.ts.map +1 -1
- package/dist/utils/helpers.js +11 -10
- package/dist/utils/helpers.js.map +1 -1
- package/dist/utils/perf-logger.d.ts +100 -0
- package/dist/utils/perf-logger.d.ts.map +1 -0
- package/dist/utils/perf-logger.js +132 -0
- package/dist/utils/perf-logger.js.map +1 -0
- package/package.json +3 -3
|
@@ -0,0 +1,273 @@
|
|
|
1
|
+
# Sprint Creation Template
|
|
2
|
+
|
|
3
|
+
## AI-Mediated Sprint Creation Guide (EPIC-018)
|
|
4
|
+
|
|
5
|
+
**For AI Partners:** Use this template to create well-formed sprints with rich task content. Unlike epics (which require extensive planning), sprints are focused work units. Your job is to:
|
|
6
|
+
|
|
7
|
+
1. **Gather context** from the graph and session
|
|
8
|
+
2. **Clarify intent** through natural conversation
|
|
9
|
+
3. **Generate rich tasks** with WHY-WHAT-HOW structure
|
|
10
|
+
4. **Assess confidence** and trigger inquiry when uncertain
|
|
11
|
+
5. **Create the sprint file** and sync to graph
|
|
12
|
+
|
|
13
|
+
---
|
|
14
|
+
|
|
15
|
+
## Step 1: Gather Context
|
|
16
|
+
|
|
17
|
+
Before asking questions, silently gather relevant context:
|
|
18
|
+
|
|
19
|
+
```bash
|
|
20
|
+
# Check for related bugs, issues, or prior work
|
|
21
|
+
ginko graph query "<topic from user intent>"
|
|
22
|
+
|
|
23
|
+
# Check current session context
|
|
24
|
+
# (You already have this from the conversation)
|
|
25
|
+
|
|
26
|
+
# Check what's in progress
|
|
27
|
+
ginko status
|
|
28
|
+
```
|
|
29
|
+
|
|
30
|
+
**Synthesize:** What do you already know that's relevant? What patterns, ADRs, or gotchas apply?
|
|
31
|
+
|
|
32
|
+
---
|
|
33
|
+
|
|
34
|
+
## Step 2: Clarify Intent
|
|
35
|
+
|
|
36
|
+
The user has expressed intent (e.g., "fix some dashboard bugs"). Ask **only what you need** to create actionable tasks.
|
|
37
|
+
|
|
38
|
+
**Key questions (ask naturally, not mechanically):**
|
|
39
|
+
|
|
40
|
+
1. **Scope:** "Which specific issues are we targeting?" or "I found these dashboard-related items in the graph: [list]. Which are priorities?"
|
|
41
|
+
|
|
42
|
+
2. **Boundaries:** "Anything explicitly out of scope for this sprint?"
|
|
43
|
+
|
|
44
|
+
3. **Success criteria:** "How will we know we're done?"
|
|
45
|
+
|
|
46
|
+
**Stop asking when:**
|
|
47
|
+
- You have enough to create 2-6 concrete tasks
|
|
48
|
+
- User signals readiness ("let's go with that", "sounds good")
|
|
49
|
+
- You're confident (>75%) in task definitions
|
|
50
|
+
|
|
51
|
+
---
|
|
52
|
+
|
|
53
|
+
## Step 3: Generate Rich Tasks (WHY-WHAT-HOW)
|
|
54
|
+
|
|
55
|
+
For each task, generate the full structure:
|
|
56
|
+
|
|
57
|
+
```markdown
|
|
58
|
+
### {sprint_id}_t{NN}: {Title} ({estimate})
|
|
59
|
+
|
|
60
|
+
**Status:** [ ] Not Started
|
|
61
|
+
**Priority:** {CRITICAL|HIGH|MEDIUM|LOW}
|
|
62
|
+
**Confidence:** {0-100}%
|
|
63
|
+
|
|
64
|
+
**Problem:** {WHY - 1-2 sentences on the pain point or motivation}
|
|
65
|
+
|
|
66
|
+
**Solution:** {WHAT - 1-2 sentences on the desired outcome}
|
|
67
|
+
|
|
68
|
+
**Approach:** {HOW - 2-3 sentences on implementation strategy}
|
|
69
|
+
|
|
70
|
+
**Scope:**
|
|
71
|
+
- Includes: {what's in scope}
|
|
72
|
+
- Excludes: {what's explicitly out}
|
|
73
|
+
|
|
74
|
+
**Acceptance Criteria:**
|
|
75
|
+
- [ ] {Specific, testable criterion 1}
|
|
76
|
+
- [ ] {Specific, testable criterion 2}
|
|
77
|
+
- [ ] {Tests pass}
|
|
78
|
+
```
|
|
79
|
+
|
|
80
|
+
### Confidence Scoring (Critical)
|
|
81
|
+
|
|
82
|
+
Be honest about your confidence in each task:
|
|
83
|
+
|
|
84
|
+
| Score | Meaning | Your Action |
|
|
85
|
+
|-------|---------|-------------|
|
|
86
|
+
| 90-100% | Crystal clear, obvious implementation | Proceed |
|
|
87
|
+
| 70-89% | Good clarity, minor assumptions | Note assumptions in Approach |
|
|
88
|
+
| 50-69% | Moderate ambiguity | Flag and ask clarifying question |
|
|
89
|
+
| Below 50% | Significant uncertainty | Stop and discuss with human |
|
|
90
|
+
|
|
91
|
+
**Philosophy:** Low confidence is a STRENGTH. A score of 60 with honest questions is better than 90 with hidden assumptions.
|
|
92
|
+
|
|
93
|
+
---
|
|
94
|
+
|
|
95
|
+
## Step 4: Composite Confidence Check
|
|
96
|
+
|
|
97
|
+
After generating all tasks, calculate the average confidence.
|
|
98
|
+
|
|
99
|
+
**If composite confidence < 75%:**
|
|
100
|
+
|
|
101
|
+
```
|
|
102
|
+
I've drafted the sprint, but my overall confidence is {N}%.
|
|
103
|
+
|
|
104
|
+
Some tasks need clarification:
|
|
105
|
+
- Task 2: {title} (confidence: {N}%) - {what's unclear}
|
|
106
|
+
- Task 4: {title} (confidence: {N}%) - {what's unclear}
|
|
107
|
+
|
|
108
|
+
This is a good thing! Better to clarify now than build the wrong thing.
|
|
109
|
+
|
|
110
|
+
For each flagged task, can you help me understand:
|
|
111
|
+
- {Specific question about Task 2}
|
|
112
|
+
- {Specific question about Task 4}
|
|
113
|
+
|
|
114
|
+
Or if you'd prefer, I can proceed with my best judgment.
|
|
115
|
+
```
|
|
116
|
+
|
|
117
|
+
**If composite confidence >= 75%:**
|
|
118
|
+
Present the sprint plan and ask for approval before creating files.
|
|
119
|
+
|
|
120
|
+
---
|
|
121
|
+
|
|
122
|
+
## Step 5: Create Sprint File
|
|
123
|
+
|
|
124
|
+
After approval, create the sprint file.
|
|
125
|
+
|
|
126
|
+
**Filename:** `docs/sprints/SPRINT-YYYY-MM-{sprint_id}-{slug}.md`
|
|
127
|
+
|
|
128
|
+
Example: `docs/sprints/SPRINT-2026-02-adhoc_260205_s01-dashboard-fixes.md`
|
|
129
|
+
|
|
130
|
+
**Generate Sprint ID:**
|
|
131
|
+
- For ad-hoc work: `adhoc_{YYMMDD}_s{NN}` (e.g., `adhoc_260205_s01`)
|
|
132
|
+
- For epic work: `e{NNN}_s{NN}` (e.g., `e018_s02`)
|
|
133
|
+
|
|
134
|
+
### Sprint File Template
|
|
135
|
+
|
|
136
|
+
```markdown
|
|
137
|
+
# SPRINT: {Sprint Name}
|
|
138
|
+
|
|
139
|
+
## Sprint Overview
|
|
140
|
+
|
|
141
|
+
**Sprint Goal**: {One sentence describing what this sprint achieves}
|
|
142
|
+
**Duration**: {YYYY-MM-DD} to {YYYY-MM-DD}
|
|
143
|
+
**Type**: {Bug Fix|Feature|Infrastructure|Polish}
|
|
144
|
+
**Progress:** 0% (0/{N} tasks complete)
|
|
145
|
+
**ID:** `{sprint_id}`
|
|
146
|
+
|
|
147
|
+
**Success Criteria:**
|
|
148
|
+
- {Sprint-level success criterion 1}
|
|
149
|
+
- {Sprint-level success criterion 2}
|
|
150
|
+
|
|
151
|
+
---
|
|
152
|
+
|
|
153
|
+
## Sprint Tasks
|
|
154
|
+
|
|
155
|
+
{For each task, use the WHY-WHAT-HOW format from Step 3}
|
|
156
|
+
|
|
157
|
+
---
|
|
158
|
+
|
|
159
|
+
## Related Documents
|
|
160
|
+
|
|
161
|
+
- **Epic**: {Epic name or "Ad-Hoc Work"}
|
|
162
|
+
- **ADRs**: {List relevant ADRs}
|
|
163
|
+
- **Patterns**: {List relevant patterns}
|
|
164
|
+
|
|
165
|
+
---
|
|
166
|
+
|
|
167
|
+
**Sprint Status**: Active
|
|
168
|
+
**Start Date**: {YYYY-MM-DD}
|
|
169
|
+
**Created By**: {user email}
|
|
170
|
+
```
|
|
171
|
+
|
|
172
|
+
---
|
|
173
|
+
|
|
174
|
+
## Step 6: Sync to Graph
|
|
175
|
+
|
|
176
|
+
After creating the sprint file:
|
|
177
|
+
|
|
178
|
+
```bash
|
|
179
|
+
ginko push sprint
|
|
180
|
+
```
|
|
181
|
+
|
|
182
|
+
Then start the first task:
|
|
183
|
+
|
|
184
|
+
```bash
|
|
185
|
+
ginko task start {sprint_id}_t01
|
|
186
|
+
```
|
|
187
|
+
|
|
188
|
+
---
|
|
189
|
+
|
|
190
|
+
## Content Quality Standards
|
|
191
|
+
|
|
192
|
+
Tasks are assessed as:
|
|
193
|
+
|
|
194
|
+
| Quality | Criteria |
|
|
195
|
+
|---------|----------|
|
|
196
|
+
| **Rich** | Has problem, solution, approach, scope, criteria |
|
|
197
|
+
| **Adequate** | Has basics but missing approach or scope |
|
|
198
|
+
| **Thin** | Missing problem or acceptance criteria - needs enrichment |
|
|
199
|
+
|
|
200
|
+
**Target:** All tasks should be Rich or Adequate. Thin tasks trigger inquiry.
|
|
201
|
+
|
|
202
|
+
---
|
|
203
|
+
|
|
204
|
+
## Work Mode Sensitivity
|
|
205
|
+
|
|
206
|
+
Adjust depth based on signals:
|
|
207
|
+
|
|
208
|
+
**Hack & Ship** (quick fix, spike, experiment):
|
|
209
|
+
- 1-3 tasks, minimal ceremony
|
|
210
|
+
- Confidence threshold: 60%
|
|
211
|
+
- Skip detailed scope if obvious
|
|
212
|
+
|
|
213
|
+
**Think & Build** (standard work):
|
|
214
|
+
- 2-6 tasks, full WHY-WHAT-HOW
|
|
215
|
+
- Confidence threshold: 75%
|
|
216
|
+
- Include scope and acceptance criteria
|
|
217
|
+
|
|
218
|
+
**Full Planning** (complex, multi-person):
|
|
219
|
+
- Detailed task breakdown
|
|
220
|
+
- Confidence threshold: 85%
|
|
221
|
+
- Include dependencies, risks
|
|
222
|
+
|
|
223
|
+
---
|
|
224
|
+
|
|
225
|
+
## Example Conversation Flow
|
|
226
|
+
|
|
227
|
+
**Human:** "Let's start a sprint to fix some dashboard bugs"
|
|
228
|
+
|
|
229
|
+
**AI:** *[Silently queries: `ginko graph query "dashboard bugs"`]*
|
|
230
|
+
|
|
231
|
+
**AI:** "I found a few dashboard-related items in the graph:
|
|
232
|
+
- Stale data in Projects tab after rename
|
|
233
|
+
- Member list not refreshing
|
|
234
|
+
- Settings panel layout issue on mobile
|
|
235
|
+
|
|
236
|
+
Which of these are priorities for this sprint? Any others I missed?"
|
|
237
|
+
|
|
238
|
+
**Human:** "The first two - they're related. Skip the mobile thing for now."
|
|
239
|
+
|
|
240
|
+
**AI:** "Got it. Both relate to data freshness after project changes. Let me draft the tasks:
|
|
241
|
+
|
|
242
|
+
**Sprint: Dashboard Data Refresh Fixes**
|
|
243
|
+
|
|
244
|
+
1. **Fix member list refresh on project rename** (2h, confidence: 85%)
|
|
245
|
+
- Problem: Member list shows stale data after project name changes
|
|
246
|
+
- Solution: Trigger refresh when project name updates
|
|
247
|
+
|
|
248
|
+
2. **Add loading state during refresh** (1h, confidence: 90%)
|
|
249
|
+
- Problem: No feedback during data reload
|
|
250
|
+
- Solution: Show spinner while fetching updated data
|
|
251
|
+
|
|
252
|
+
3. **Test and verify fixes** (1h, confidence: 95%)
|
|
253
|
+
- Verify both issues resolved, no regressions
|
|
254
|
+
|
|
255
|
+
Overall confidence: 90%. Ready to create the sprint?"
|
|
256
|
+
|
|
257
|
+
**Human:** "Looks good, let's go."
|
|
258
|
+
|
|
259
|
+
**AI:** *[Creates sprint file, runs `ginko push sprint`, starts first task]*
|
|
260
|
+
|
|
261
|
+
---
|
|
262
|
+
|
|
263
|
+
## Key Principles
|
|
264
|
+
|
|
265
|
+
1. **Context first:** Query the graph before asking questions
|
|
266
|
+
2. **Inquiry is strength:** Low confidence triggers conversation, not silent assumptions
|
|
267
|
+
3. **Rich tasks:** Every task has WHY-WHAT-HOW, not just a title
|
|
268
|
+
4. **Natural conversation:** Don't interrogate - collaborate
|
|
269
|
+
5. **Human approval:** Present plan before creating files
|
|
270
|
+
|
|
271
|
+
---
|
|
272
|
+
|
|
273
|
+
**Remember:** The goal is actionable tasks the AI can execute autonomously. Quality thinking over complete forms.
|
|
@@ -0,0 +1,48 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* @fileType: utility
|
|
3
|
+
* @status: current
|
|
4
|
+
* @updated: 2026-02-15
|
|
5
|
+
* @tags: [cloud, auth, guard, local-first, ADR-078]
|
|
6
|
+
* @related: [auth-storage.ts, identity.ts]
|
|
7
|
+
* @priority: critical
|
|
8
|
+
* @complexity: low
|
|
9
|
+
* @dependencies: [chalk]
|
|
10
|
+
*/
|
|
11
|
+
import { type AuthSession } from './auth-storage.js';
|
|
12
|
+
export interface CloudStatus {
|
|
13
|
+
/** Whether the user is authenticated with Ginko Cloud */
|
|
14
|
+
available: boolean;
|
|
15
|
+
/** The auth session if available, null otherwise */
|
|
16
|
+
session: AuthSession | null;
|
|
17
|
+
}
|
|
18
|
+
/**
|
|
19
|
+
* Non-blocking cloud availability check.
|
|
20
|
+
*
|
|
21
|
+
* Returns cloud status without blocking command execution.
|
|
22
|
+
* Use this for LOCAL and CLOUD-ENHANCED commands that should
|
|
23
|
+
* work without authentication but can do more with it.
|
|
24
|
+
*
|
|
25
|
+
* @param _commandName - The command name (for future telemetry)
|
|
26
|
+
* @returns CloudStatus indicating whether cloud features are available
|
|
27
|
+
*/
|
|
28
|
+
export declare function withOptionalCloud(_commandName: string): Promise<CloudStatus>;
|
|
29
|
+
/**
|
|
30
|
+
* Blocking cloud requirement check.
|
|
31
|
+
*
|
|
32
|
+
* Shows a value-proposition upgrade message and exits cleanly
|
|
33
|
+
* if the user is not authenticated. Use this for commands that
|
|
34
|
+
* fundamentally require Ginko Cloud (push, pull, graph, team, etc.).
|
|
35
|
+
*
|
|
36
|
+
* @param commandName - The command name for the error message
|
|
37
|
+
*/
|
|
38
|
+
export declare function requireCloud(commandName: string): Promise<void>;
|
|
39
|
+
/**
|
|
40
|
+
* Show a one-time upgrade hint after successful local command usage.
|
|
41
|
+
*
|
|
42
|
+
* Only shown once per CLI process to avoid nagging.
|
|
43
|
+
* Call this at the end of LOCAL commands to gently surface cloud features.
|
|
44
|
+
*
|
|
45
|
+
* @param feature - The cloud feature that would enhance this command
|
|
46
|
+
*/
|
|
47
|
+
export declare function showCloudUpgradeHint(feature: string): Promise<void>;
|
|
48
|
+
//# sourceMappingURL=cloud-guard.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"cloud-guard.d.ts","sourceRoot":"","sources":["../../src/utils/cloud-guard.ts"],"names":[],"mappings":"AAAA;;;;;;;;;GASG;AAeH,OAAO,EAAoC,KAAK,WAAW,EAAE,MAAM,mBAAmB,CAAC;AAMvF,MAAM,WAAW,WAAW;IAC1B,yDAAyD;IACzD,SAAS,EAAE,OAAO,CAAC;IACnB,oDAAoD;IACpD,OAAO,EAAE,WAAW,GAAG,IAAI,CAAC;CAC7B;AASD;;;;;;;;;GASG;AACH,wBAAsB,iBAAiB,CAAC,YAAY,EAAE,MAAM,GAAG,OAAO,CAAC,WAAW,CAAC,CAalF;AAMD;;;;;;;;GAQG;AACH,wBAAsB,YAAY,CAAC,WAAW,EAAE,MAAM,GAAG,OAAO,CAAC,IAAI,CAAC,CAoBrE;AAMD;;;;;;;GAOG;AACH,wBAAsB,oBAAoB,CAAC,OAAO,EAAE,MAAM,GAAG,OAAO,CAAC,IAAI,CAAC,CAWzE"}
|
|
@@ -0,0 +1,107 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* @fileType: utility
|
|
3
|
+
* @status: current
|
|
4
|
+
* @updated: 2026-02-15
|
|
5
|
+
* @tags: [cloud, auth, guard, local-first, ADR-078]
|
|
6
|
+
* @related: [auth-storage.ts, identity.ts]
|
|
7
|
+
* @priority: critical
|
|
8
|
+
* @complexity: low
|
|
9
|
+
* @dependencies: [chalk]
|
|
10
|
+
*/
|
|
11
|
+
/**
|
|
12
|
+
* Cloud Guard Utility (ADR-078: Local-First CLI Architecture)
|
|
13
|
+
*
|
|
14
|
+
* Provides three tiers of cloud availability checks:
|
|
15
|
+
*
|
|
16
|
+
* LOCAL commands: Use withOptionalCloud() — works with zero auth
|
|
17
|
+
* CLOUD-ENHANCED commands: Use withOptionalCloud() — works locally, richer with cloud
|
|
18
|
+
* CLOUD-ONLY commands: Use requireCloud() — shows upgrade message and exits
|
|
19
|
+
*
|
|
20
|
+
* Replaces hard requireAuth() gates that blocked open-source CLI usage.
|
|
21
|
+
*/
|
|
22
|
+
import chalk from 'chalk';
|
|
23
|
+
import { isAuthenticated, loadAuthSession } from './auth-storage.js';
|
|
24
|
+
// Track whether we've shown the upgrade hint this session
|
|
25
|
+
let upgradeHintShown = false;
|
|
26
|
+
// =============================================================================
|
|
27
|
+
// Non-blocking check — for LOCAL + CLOUD-ENHANCED commands
|
|
28
|
+
// =============================================================================
|
|
29
|
+
/**
|
|
30
|
+
* Non-blocking cloud availability check.
|
|
31
|
+
*
|
|
32
|
+
* Returns cloud status without blocking command execution.
|
|
33
|
+
* Use this for LOCAL and CLOUD-ENHANCED commands that should
|
|
34
|
+
* work without authentication but can do more with it.
|
|
35
|
+
*
|
|
36
|
+
* @param _commandName - The command name (for future telemetry)
|
|
37
|
+
* @returns CloudStatus indicating whether cloud features are available
|
|
38
|
+
*/
|
|
39
|
+
export async function withOptionalCloud(_commandName) {
|
|
40
|
+
try {
|
|
41
|
+
const session = await loadAuthSession();
|
|
42
|
+
return {
|
|
43
|
+
available: session !== null,
|
|
44
|
+
session,
|
|
45
|
+
};
|
|
46
|
+
}
|
|
47
|
+
catch {
|
|
48
|
+
return {
|
|
49
|
+
available: false,
|
|
50
|
+
session: null,
|
|
51
|
+
};
|
|
52
|
+
}
|
|
53
|
+
}
|
|
54
|
+
// =============================================================================
|
|
55
|
+
// Blocking gate — for CLOUD-ONLY commands
|
|
56
|
+
// =============================================================================
|
|
57
|
+
/**
|
|
58
|
+
* Blocking cloud requirement check.
|
|
59
|
+
*
|
|
60
|
+
* Shows a value-proposition upgrade message and exits cleanly
|
|
61
|
+
* if the user is not authenticated. Use this for commands that
|
|
62
|
+
* fundamentally require Ginko Cloud (push, pull, graph, team, etc.).
|
|
63
|
+
*
|
|
64
|
+
* @param commandName - The command name for the error message
|
|
65
|
+
*/
|
|
66
|
+
export async function requireCloud(commandName) {
|
|
67
|
+
const authenticated = await isAuthenticated();
|
|
68
|
+
if (!authenticated) {
|
|
69
|
+
console.log('');
|
|
70
|
+
console.log(chalk.cyan(` ginko ${commandName}`) + chalk.dim(' requires Ginko Cloud.'));
|
|
71
|
+
console.log('');
|
|
72
|
+
console.log(chalk.white(' Ginko Cloud adds:'));
|
|
73
|
+
console.log(chalk.dim(' - Knowledge graph search across your codebase'));
|
|
74
|
+
console.log(chalk.dim(' - Team collaboration and visibility'));
|
|
75
|
+
console.log(chalk.dim(' - AI-powered coaching insights'));
|
|
76
|
+
console.log('');
|
|
77
|
+
console.log(chalk.white(' Get started: ') + chalk.cyan('ginko login'));
|
|
78
|
+
console.log(chalk.dim(' Learn more: https://ginkoai.com/cloud'));
|
|
79
|
+
console.log('');
|
|
80
|
+
console.log(chalk.dim(' Everything you\'ve built locally will sync when you connect.'));
|
|
81
|
+
console.log('');
|
|
82
|
+
process.exit(0);
|
|
83
|
+
}
|
|
84
|
+
}
|
|
85
|
+
// =============================================================================
|
|
86
|
+
// End-of-session nudge — shown once per session
|
|
87
|
+
// =============================================================================
|
|
88
|
+
/**
|
|
89
|
+
* Show a one-time upgrade hint after successful local command usage.
|
|
90
|
+
*
|
|
91
|
+
* Only shown once per CLI process to avoid nagging.
|
|
92
|
+
* Call this at the end of LOCAL commands to gently surface cloud features.
|
|
93
|
+
*
|
|
94
|
+
* @param feature - The cloud feature that would enhance this command
|
|
95
|
+
*/
|
|
96
|
+
export async function showCloudUpgradeHint(feature) {
|
|
97
|
+
if (upgradeHintShown)
|
|
98
|
+
return;
|
|
99
|
+
const authenticated = await isAuthenticated();
|
|
100
|
+
if (authenticated)
|
|
101
|
+
return;
|
|
102
|
+
upgradeHintShown = true;
|
|
103
|
+
console.log('');
|
|
104
|
+
console.log(chalk.dim(` Tip: ${feature}`));
|
|
105
|
+
console.log(chalk.dim(' Connect with: ginko login'));
|
|
106
|
+
}
|
|
107
|
+
//# sourceMappingURL=cloud-guard.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"cloud-guard.js","sourceRoot":"","sources":["../../src/utils/cloud-guard.ts"],"names":[],"mappings":"AAAA;;;;;;;;;GASG;AAEH;;;;;;;;;;GAUG;AAEH,OAAO,KAAK,MAAM,OAAO,CAAC;AAC1B,OAAO,EAAE,eAAe,EAAE,eAAe,EAAoB,MAAM,mBAAmB,CAAC;AAavF,0DAA0D;AAC1D,IAAI,gBAAgB,GAAG,KAAK,CAAC;AAE7B,gFAAgF;AAChF,2DAA2D;AAC3D,gFAAgF;AAEhF;;;;;;;;;GASG;AACH,MAAM,CAAC,KAAK,UAAU,iBAAiB,CAAC,YAAoB;IAC1D,IAAI,CAAC;QACH,MAAM,OAAO,GAAG,MAAM,eAAe,EAAE,CAAC;QACxC,OAAO;YACL,SAAS,EAAE,OAAO,KAAK,IAAI;YAC3B,OAAO;SACR,CAAC;IACJ,CAAC;IAAC,MAAM,CAAC;QACP,OAAO;YACL,SAAS,EAAE,KAAK;YAChB,OAAO,EAAE,IAAI;SACd,CAAC;IACJ,CAAC;AACH,CAAC;AAED,gFAAgF;AAChF,0CAA0C;AAC1C,gFAAgF;AAEhF;;;;;;;;GAQG;AACH,MAAM,CAAC,KAAK,UAAU,YAAY,CAAC,WAAmB;IACpD,MAAM,aAAa,GAAG,MAAM,eAAe,EAAE,CAAC;IAE9C,IAAI,CAAC,aAAa,EAAE,CAAC;QACnB,OAAO,CAAC,GAAG,CAAC,EAAE,CAAC,CAAC;QAChB,OAAO,CAAC,GAAG,CAAC,KAAK,CAAC,IAAI,CAAC,WAAW,WAAW,EAAE,CAAC,GAAG,KAAK,CAAC,GAAG,CAAC,wBAAwB,CAAC,CAAC,CAAC;QACxF,OAAO,CAAC,GAAG,CAAC,EAAE,CAAC,CAAC;QAChB,OAAO,CAAC,GAAG,CAAC,KAAK,CAAC,KAAK,CAAC,qBAAqB,CAAC,CAAC,CAAC;QAChD,OAAO,CAAC,GAAG,CAAC,KAAK,CAAC,GAAG,CAAC,mDAAmD,CAAC,CAAC,CAAC;QAC5E,OAAO,CAAC,GAAG,CAAC,KAAK,CAAC,GAAG,CAAC,yCAAyC,CAAC,CAAC,CAAC;QAClE,OAAO,CAAC,GAAG,CAAC,KAAK,CAAC,GAAG,CAAC,oCAAoC,CAAC,CAAC,CAAC;QAC7D,OAAO,CAAC,GAAG,CAAC,EAAE,CAAC,CAAC;QAChB,OAAO,CAAC,GAAG,CAAC,KAAK,CAAC,KAAK,CAAC,iBAAiB,CAAC,GAAG,KAAK,CAAC,IAAI,CAAC,aAAa,CAAC,CAAC,CAAC;QACxE,OAAO,CAAC,GAAG,CAAC,KAAK,CAAC,GAAG,CAAC,0CAA0C,CAAC,CAAC,CAAC;QACnE,OAAO,CAAC,GAAG,CAAC,EAAE,CAAC,CAAC;QAChB,OAAO,CAAC,GAAG,CAAC,KAAK,CAAC,GAAG,CAAC,gEAAgE,CAAC,CAAC,CAAC;QACzF,OAAO,CAAC,GAAG,CAAC,EAAE,CAAC,CAAC;QAEhB,OAAO,CAAC,IAAI,CAAC,CAAC,CAAC,CAAC;IAClB,CAAC;AACH,CAAC;AAED,gFAAgF;AAChF,gDAAgD;AAChD,gFAAgF;AAEhF;;;;;;;GAOG;AACH,MAAM,CAAC,KAAK,UAAU,oBAAoB,CAAC,OAAe;IACxD,IAAI,gBAAgB;QAAE,OAAO;IAE7B,MAAM,aAAa,GAAG,MAAM,eAAe,EAAE,CAAC;IAC9C,IAAI,aAAa;QAAE,OAAO;IAE1B,gBAAgB,GAAG,IAAI,CAAC;IAExB,OAAO,CAAC,GAAG,CAAC,EAAE,CAAC,CAAC;IAChB,OAAO,CAAC,GAAG,CAAC,KAAK,CAAC,GAAG,CAAC,UAAU,OAAO,EAAE,CAAC,CAAC,CAAC;IAC5C,OAAO,CAAC,GAAG,CAAC,KAAK,CAAC,GAAG,CAAC,6BAA6B,CAAC,CAAC,CAAC;AACxD,CAAC"}
|
|
@@ -36,11 +36,11 @@ export declare function loadLocalConfig(): Promise<LocalConfig>;
|
|
|
36
36
|
* @example
|
|
37
37
|
* // Using path key
|
|
38
38
|
* const sprintPath = await resolveProjectPath('currentSprint');
|
|
39
|
-
* // → /
|
|
39
|
+
* // → /home/user/my-project/docs/sprints/CURRENT-SPRINT.md
|
|
40
40
|
*
|
|
41
41
|
* // Using relative path directly
|
|
42
42
|
* const customPath = await resolveProjectPath('docs/custom/file.md');
|
|
43
|
-
* // → /
|
|
43
|
+
* // → /home/user/my-project/docs/custom/file.md
|
|
44
44
|
*/
|
|
45
45
|
export declare function resolveProjectPath(relativePath: string): Promise<string>;
|
|
46
46
|
/**
|
|
@@ -187,11 +187,11 @@ async function createLocalConfig(projectRoot) {
|
|
|
187
187
|
* @example
|
|
188
188
|
* // Using path key
|
|
189
189
|
* const sprintPath = await resolveProjectPath('currentSprint');
|
|
190
|
-
* // → /
|
|
190
|
+
* // → /home/user/my-project/docs/sprints/CURRENT-SPRINT.md
|
|
191
191
|
*
|
|
192
192
|
* // Using relative path directly
|
|
193
193
|
* const customPath = await resolveProjectPath('docs/custom/file.md');
|
|
194
|
-
* // → /
|
|
194
|
+
* // → /home/user/my-project/docs/custom/file.md
|
|
195
195
|
*/
|
|
196
196
|
export async function resolveProjectPath(relativePath) {
|
|
197
197
|
const [localConfig, projectConfig] = await Promise.all([
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"helpers.d.ts","sourceRoot":"","sources":["../../src/utils/helpers.ts"],"names":[],"mappings":"AAAA;;;;;;;;GAQG;AAOH,wBAAsB,WAAW,IAAI,OAAO,CAAC,MAAM,CAAC,CAGnD;AAED,wBAAsB,cAAc,IAAI,OAAO,CAAC,MAAM,CAAC,CAEtD;AAED,wBAAsB,YAAY,IAAI,OAAO,CAAC,MAAM,CAAC,
|
|
1
|
+
{"version":3,"file":"helpers.d.ts","sourceRoot":"","sources":["../../src/utils/helpers.ts"],"names":[],"mappings":"AAAA;;;;;;;;GAQG;AAOH,wBAAsB,WAAW,IAAI,OAAO,CAAC,MAAM,CAAC,CAGnD;AAED,wBAAsB,cAAc,IAAI,OAAO,CAAC,MAAM,CAAC,CAEtD;AAED,wBAAsB,YAAY,IAAI,OAAO,CAAC,MAAM,CAAC,CAoBpD;AAED,wBAAgB,aAAa,CAAC,IAAI,EAAE,IAAI,GAAG,MAAM,CAWhD;AAED,wBAAsB,cAAc,CAAC,SAAS,EAAE,GAAG,GAAG,OAAO,CAAC,MAAM,CAAC,CAkBpE;AAED,wBAAsB,cAAc,IAAI,OAAO,CAAC;IAC9C,IAAI,EAAE,MAAM,CAAC;IACb,IAAI,EAAE,MAAM,CAAC;IACb,QAAQ,EAAE,MAAM,CAAC;CAClB,CAAC,CAqCD"}
|
package/dist/utils/helpers.js
CHANGED
|
@@ -19,16 +19,8 @@ export async function getProjectRoot() {
|
|
|
19
19
|
return await requireGinkoRoot();
|
|
20
20
|
}
|
|
21
21
|
export async function getUserEmail() {
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
const email = execSync('git config user.email', { encoding: 'utf8' }).trim();
|
|
25
|
-
if (email)
|
|
26
|
-
return email;
|
|
27
|
-
}
|
|
28
|
-
catch (e) {
|
|
29
|
-
// Git not configured
|
|
30
|
-
}
|
|
31
|
-
// Try config file
|
|
22
|
+
// Ginko config is authoritative — it stores the identity set during init/login (BUG-021)
|
|
23
|
+
// This ensures init and start use the same user directory
|
|
32
24
|
try {
|
|
33
25
|
const ginkoDir = await getGinkoDir();
|
|
34
26
|
const config = await fs.readJSON(path.join(ginkoDir, 'config.json'));
|
|
@@ -38,6 +30,15 @@ export async function getUserEmail() {
|
|
|
38
30
|
catch (e) {
|
|
39
31
|
// Config not found or invalid
|
|
40
32
|
}
|
|
33
|
+
// Fall back to git config
|
|
34
|
+
try {
|
|
35
|
+
const email = execSync('git config user.email', { encoding: 'utf8' }).trim();
|
|
36
|
+
if (email)
|
|
37
|
+
return email;
|
|
38
|
+
}
|
|
39
|
+
catch (e) {
|
|
40
|
+
// Git not configured
|
|
41
|
+
}
|
|
41
42
|
return 'user@example.com';
|
|
42
43
|
}
|
|
43
44
|
export function formatTimeAgo(date) {
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"helpers.js","sourceRoot":"","sources":["../../src/utils/helpers.ts"],"names":[],"mappings":"AAAA;;;;;;;;GAQG;AAEH,OAAO,EAAE,MAAM,UAAU,CAAC;AAC1B,OAAO,IAAI,MAAM,MAAM,CAAC;AACxB,OAAO,EAAE,QAAQ,EAAE,MAAM,eAAe,CAAC;AACzC,OAAO,EAAE,gBAAgB,EAAgB,MAAM,iBAAiB,CAAC;AAEjE,MAAM,CAAC,KAAK,UAAU,WAAW;IAC/B,MAAM,IAAI,GAAG,MAAM,gBAAgB,EAAE,CAAC;IACtC,OAAO,IAAI,CAAC,IAAI,CAAC,IAAI,EAAE,QAAQ,CAAC,CAAC;AACnC,CAAC;AAED,MAAM,CAAC,KAAK,UAAU,cAAc;IAClC,OAAO,MAAM,gBAAgB,EAAE,CAAC;AAClC,CAAC;AAED,MAAM,CAAC,KAAK,UAAU,YAAY;IAChC,IAAI,CAAC;QACH,
|
|
1
|
+
{"version":3,"file":"helpers.js","sourceRoot":"","sources":["../../src/utils/helpers.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,100 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* @fileType: utility
|
|
3
|
+
* @status: current
|
|
4
|
+
* @updated: 2026-02-05
|
|
5
|
+
* @tags: [performance, timing, metrics, EPIC-018]
|
|
6
|
+
* @related: [context-loader-events.ts, start-reflection.ts]
|
|
7
|
+
* @priority: medium
|
|
8
|
+
* @complexity: low
|
|
9
|
+
* @dependencies: []
|
|
10
|
+
*/
|
|
11
|
+
/**
|
|
12
|
+
* Performance Logger for Context Loading (EPIC-018 Sprint 1 TASK-04)
|
|
13
|
+
*
|
|
14
|
+
* Provides timing instrumentation for context loading operations.
|
|
15
|
+
* Enabled via GINKO_PERF_LOG=true environment variable.
|
|
16
|
+
*
|
|
17
|
+
* Usage:
|
|
18
|
+
* ```typescript
|
|
19
|
+
* const perf = PerfLogger.create('contextLoad');
|
|
20
|
+
* perf.mark('apiCall');
|
|
21
|
+
* await fetchData();
|
|
22
|
+
* perf.measure('apiCall', 'API call completed');
|
|
23
|
+
* perf.summary();
|
|
24
|
+
* ```
|
|
25
|
+
*/
|
|
26
|
+
export interface PerfMark {
|
|
27
|
+
name: string;
|
|
28
|
+
timestamp: number;
|
|
29
|
+
}
|
|
30
|
+
export interface PerfMeasure {
|
|
31
|
+
name: string;
|
|
32
|
+
duration: number;
|
|
33
|
+
label?: string;
|
|
34
|
+
}
|
|
35
|
+
export interface PerfSummary {
|
|
36
|
+
operation: string;
|
|
37
|
+
totalDuration: number;
|
|
38
|
+
measures: PerfMeasure[];
|
|
39
|
+
startedAt: number;
|
|
40
|
+
endedAt: number;
|
|
41
|
+
}
|
|
42
|
+
/**
|
|
43
|
+
* Performance logger for measuring operation timing
|
|
44
|
+
*/
|
|
45
|
+
export declare class PerfLogger {
|
|
46
|
+
private operation;
|
|
47
|
+
private startTime;
|
|
48
|
+
private marks;
|
|
49
|
+
private measures;
|
|
50
|
+
private enabled;
|
|
51
|
+
private constructor();
|
|
52
|
+
/**
|
|
53
|
+
* Create a new performance logger for an operation
|
|
54
|
+
*/
|
|
55
|
+
static create(operation: string): PerfLogger;
|
|
56
|
+
/**
|
|
57
|
+
* Mark the start of a timed section
|
|
58
|
+
*/
|
|
59
|
+
mark(name: string): void;
|
|
60
|
+
/**
|
|
61
|
+
* Measure duration since a mark was set
|
|
62
|
+
* @returns duration in milliseconds
|
|
63
|
+
*/
|
|
64
|
+
measure(markName: string, label?: string): number;
|
|
65
|
+
/**
|
|
66
|
+
* Quick measure from operation start
|
|
67
|
+
*/
|
|
68
|
+
elapsed(label?: string): number;
|
|
69
|
+
/**
|
|
70
|
+
* Log a summary of all measurements
|
|
71
|
+
*/
|
|
72
|
+
summary(): PerfSummary;
|
|
73
|
+
/**
|
|
74
|
+
* Check if performance logging is enabled
|
|
75
|
+
*/
|
|
76
|
+
isEnabled(): boolean;
|
|
77
|
+
/**
|
|
78
|
+
* Get total elapsed time in ms
|
|
79
|
+
*/
|
|
80
|
+
getTotalDuration(): number;
|
|
81
|
+
}
|
|
82
|
+
/**
|
|
83
|
+
* Utility to time a promise and log result
|
|
84
|
+
*/
|
|
85
|
+
export declare function timeAsync<T>(operation: string, promise: Promise<T>, options?: {
|
|
86
|
+
silent?: boolean;
|
|
87
|
+
}): Promise<{
|
|
88
|
+
result: T;
|
|
89
|
+
duration: number;
|
|
90
|
+
}>;
|
|
91
|
+
/**
|
|
92
|
+
* Time multiple parallel operations
|
|
93
|
+
*/
|
|
94
|
+
export declare function timeParallel<T extends readonly unknown[]>(operation: string, promises: {
|
|
95
|
+
[K in keyof T]: Promise<T[K]>;
|
|
96
|
+
}, labels?: string[]): Promise<{
|
|
97
|
+
results: T;
|
|
98
|
+
duration: number;
|
|
99
|
+
}>;
|
|
100
|
+
//# sourceMappingURL=perf-logger.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"perf-logger.d.ts","sourceRoot":"","sources":["../../src/utils/perf-logger.ts"],"names":[],"mappings":"AAAA;;;;;;;;;GASG;AAEH;;;;;;;;;;;;;;GAcG;AAEH,MAAM,WAAW,QAAQ;IACvB,IAAI,EAAE,MAAM,CAAC;IACb,SAAS,EAAE,MAAM,CAAC;CACnB;AAED,MAAM,WAAW,WAAW;IAC1B,IAAI,EAAE,MAAM,CAAC;IACb,QAAQ,EAAE,MAAM,CAAC;IACjB,KAAK,CAAC,EAAE,MAAM,CAAC;CAChB;AAED,MAAM,WAAW,WAAW;IAC1B,SAAS,EAAE,MAAM,CAAC;IAClB,aAAa,EAAE,MAAM,CAAC;IACtB,QAAQ,EAAE,WAAW,EAAE,CAAC;IACxB,SAAS,EAAE,MAAM,CAAC;IAClB,OAAO,EAAE,MAAM,CAAC;CACjB;AAED;;GAEG;AACH,qBAAa,UAAU;IACrB,OAAO,CAAC,SAAS,CAAS;IAC1B,OAAO,CAAC,SAAS,CAAS;IAC1B,OAAO,CAAC,KAAK,CAAkC;IAC/C,OAAO,CAAC,QAAQ,CAAqB;IACrC,OAAO,CAAC,OAAO,CAAU;IAEzB,OAAO;IAOP;;OAEG;IACH,MAAM,CAAC,MAAM,CAAC,SAAS,EAAE,MAAM,GAAG,UAAU;IAI5C;;OAEG;IACH,IAAI,CAAC,IAAI,EAAE,MAAM,GAAG,IAAI;IAIxB;;;OAGG;IACH,OAAO,CAAC,QAAQ,EAAE,MAAM,EAAE,KAAK,CAAC,EAAE,MAAM,GAAG,MAAM;IAoBjD;;OAEG;IACH,OAAO,CAAC,KAAK,CAAC,EAAE,MAAM,GAAG,MAAM;IAQ/B;;OAEG;IACH,OAAO,IAAI,WAAW;IAsBtB;;OAEG;IACH,SAAS,IAAI,OAAO;IAIpB;;OAEG;IACH,gBAAgB,IAAI,MAAM;CAG3B;AAED;;GAEG;AACH,wBAAsB,SAAS,CAAC,CAAC,EAC/B,SAAS,EAAE,MAAM,EACjB,OAAO,EAAE,OAAO,CAAC,CAAC,CAAC,EACnB,OAAO,CAAC,EAAE;IAAE,MAAM,CAAC,EAAE,OAAO,CAAA;CAAE,GAC7B,OAAO,CAAC;IAAE,MAAM,EAAE,CAAC,CAAC;IAAC,QAAQ,EAAE,MAAM,CAAA;CAAE,CAAC,CAU1C;AAED;;GAEG;AACH,wBAAsB,YAAY,CAAC,CAAC,SAAS,SAAS,OAAO,EAAE,EAC7D,SAAS,EAAE,MAAM,EACjB,QAAQ,EAAE;KAAG,CAAC,IAAI,MAAM,CAAC,GAAG,OAAO,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC;CAAE,EAC3C,MAAM,CAAC,EAAE,MAAM,EAAE,GAChB,OAAO,CAAC;IAAE,OAAO,EAAE,CAAC,CAAC;IAAC,QAAQ,EAAE,MAAM,CAAA;CAAE,CAAC,CAe3C"}
|