workday-daemon 0.18.0 → 0.19.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/dist/cli.js +70 -5
- package/dist/cli.js.map +1 -1
- package/dist/core/constants.d.ts +3 -1
- package/dist/core/constants.js +3 -1
- package/dist/core/constants.js.map +1 -1
- package/dist/core/types.d.ts +26 -1
- package/dist/http-server.d.ts +7 -0
- package/dist/http-server.js +46 -1
- package/dist/http-server.js.map +1 -1
- package/dist/push/month-report.js +34 -4
- package/dist/push/month-report.js.map +1 -1
- package/dist/push/push-log.d.ts +15 -0
- package/dist/push/push-log.js +70 -0
- package/dist/push/push-log.js.map +1 -0
- package/dist/push/reconcile.d.ts +21 -0
- package/dist/push/reconcile.js +292 -0
- package/dist/push/reconcile.js.map +1 -0
- package/dist/push/tempo-client.d.ts +20 -0
- package/dist/push/tempo-client.js +19 -9
- package/dist/push/tempo-client.js.map +1 -1
- package/dist/push/tempo-pusher.d.ts +4 -4
- package/dist/push/tempo-pusher.js +85 -164
- package/dist/push/tempo-pusher.js.map +1 -1
- package/dist/push/tempo-snapshot.d.ts +18 -0
- package/dist/push/tempo-snapshot.js +98 -0
- package/dist/push/tempo-snapshot.js.map +1 -0
- package/package.json +2 -2
|
@@ -0,0 +1,292 @@
|
|
|
1
|
+
// Mirror-sync diff engine. Desired state (the local report) is compared
|
|
2
|
+
// against the ACTUAL Tempo state (worklog snapshot); push-log serves only as
|
|
3
|
+
// the ownership map localKey → tempoWorklogId, never as a source of truth
|
|
4
|
+
// about worklog content. Matching is identity-based (tempoWorklogId): field
|
|
5
|
+
// edits — time, text, activity, even a day move — keep the id on the Tempo
|
|
6
|
+
// side (verified live 2026-07-07); only a ticket move recreates the worklog.
|
|
7
|
+
import { TEMPO_TOLERANCE_SECONDS } from '../core/constants.js';
|
|
8
|
+
import { pushLogKey } from './push-log.js';
|
|
9
|
+
export function formatHours(seconds) {
|
|
10
|
+
const hours = seconds / 3600;
|
|
11
|
+
const rounded1 = parseFloat(hours.toFixed(1));
|
|
12
|
+
if (Math.abs(hours - rounded1) < 0.01)
|
|
13
|
+
return `${hours.toFixed(1)}h`;
|
|
14
|
+
return `${hours.toFixed(2)}h`;
|
|
15
|
+
}
|
|
16
|
+
function timeDrifts(a, b) {
|
|
17
|
+
return Math.abs(a - b) > TEMPO_TOLERANCE_SECONDS;
|
|
18
|
+
}
|
|
19
|
+
function manualTextDrifts(entry, wl) {
|
|
20
|
+
return (wl.description ?? '') !== (entry.description ?? '')
|
|
21
|
+
|| (wl.activity ?? '') !== (entry.activity ?? '');
|
|
22
|
+
}
|
|
23
|
+
/** The worklog no longer matches what we sent — someone edited it in Tempo. */
|
|
24
|
+
function remoteChanged(own, wl, entryDate, kind) {
|
|
25
|
+
if (own.timeSpentSeconds !== wl.timeSpentSeconds)
|
|
26
|
+
return true;
|
|
27
|
+
if (wl.startDate !== entryDate)
|
|
28
|
+
return true;
|
|
29
|
+
if (kind === 'manual') {
|
|
30
|
+
return (own.description ?? '') !== (wl.description ?? '')
|
|
31
|
+
|| (own.activity ?? '') !== (wl.activity ?? '');
|
|
32
|
+
}
|
|
33
|
+
return false;
|
|
34
|
+
}
|
|
35
|
+
/** Worklog content equals a manual entry (adoption criterion). */
|
|
36
|
+
function contentMatches(entry, wl) {
|
|
37
|
+
return !timeDrifts(wl.timeSpentSeconds, entry.totalSeconds) && !manualTextDrifts(entry, wl);
|
|
38
|
+
}
|
|
39
|
+
/**
|
|
40
|
+
* Build the push plan: desired report vs Tempo snapshot, ownership from
|
|
41
|
+
* push-log. Orphaned desired entries re-adopt unowned worklogs on the same
|
|
42
|
+
* (date, issue) — by exact content for manual entries, by being the only
|
|
43
|
+
* candidate for session aggregates — instead of blindly creating duplicates.
|
|
44
|
+
*/
|
|
45
|
+
export function buildPushPlan(report, jiraMap, pushLog, tempoWorklogs, options = {}) {
|
|
46
|
+
const plan = [];
|
|
47
|
+
const tombstones = options.tombstones ?? [];
|
|
48
|
+
const snapById = new Map();
|
|
49
|
+
const byDateIssue = new Map();
|
|
50
|
+
for (const wl of tempoWorklogs) {
|
|
51
|
+
snapById.set(wl.tempoWorklogId, wl);
|
|
52
|
+
const key = `${wl.startDate}|${wl.issueId}`;
|
|
53
|
+
const list = byDateIssue.get(key) ?? [];
|
|
54
|
+
list.push(wl);
|
|
55
|
+
byDateIssue.set(key, list);
|
|
56
|
+
}
|
|
57
|
+
// Every worklog id claimed by ANY ownership key — never an adoption candidate.
|
|
58
|
+
const ownedIds = new Set();
|
|
59
|
+
for (const logEntry of Object.values(pushLog))
|
|
60
|
+
ownedIds.add(logEntry.tempoWorklogId);
|
|
61
|
+
const accounted = new Set();
|
|
62
|
+
const pending = new Map();
|
|
63
|
+
// ── Pass 1: desired entries with a live owned worklog → field diff ──
|
|
64
|
+
for (const entry of report) {
|
|
65
|
+
const jira = jiraMap.get(entry.task);
|
|
66
|
+
if (!jira) {
|
|
67
|
+
plan.push({
|
|
68
|
+
date: entry.date, task: entry.task, targetSeconds: entry.totalSeconds,
|
|
69
|
+
action: 'error', detail: 'Unresolved in Jira',
|
|
70
|
+
kind: entry.kind, entryId: entry.entryId, description: entry.description, activity: entry.activity,
|
|
71
|
+
});
|
|
72
|
+
continue;
|
|
73
|
+
}
|
|
74
|
+
const base = {
|
|
75
|
+
date: entry.date, task: entry.task, targetSeconds: entry.totalSeconds,
|
|
76
|
+
issueId: jira.issueId, kind: entry.kind, entryId: entry.entryId,
|
|
77
|
+
};
|
|
78
|
+
const key = pushLogKey(entry.date, entry.task, entry.kind === 'manual' ? entry.entryId : undefined);
|
|
79
|
+
const own = pushLog[key];
|
|
80
|
+
const wl = own ? snapById.get(own.tempoWorklogId) : undefined;
|
|
81
|
+
if (own && wl) {
|
|
82
|
+
accounted.add(wl.tempoWorklogId);
|
|
83
|
+
if (wl.issueId !== jira.issueId) {
|
|
84
|
+
// Same id on a different issue — identity is confused; never guess.
|
|
85
|
+
plan.push({ ...base, action: 'error', existingWorklogId: wl.tempoWorklogId, detail: `Worklog #${wl.tempoWorklogId} sits on another issue in Tempo — resolve manually` });
|
|
86
|
+
continue;
|
|
87
|
+
}
|
|
88
|
+
const moved = wl.startDate !== entry.date;
|
|
89
|
+
const time = timeDrifts(wl.timeSpentSeconds, entry.totalSeconds);
|
|
90
|
+
const text = entry.kind === 'manual' && manualTextDrifts(entry, wl);
|
|
91
|
+
if (!moved && !time && !text) {
|
|
92
|
+
plan.push({ ...base, action: 'skip', detail: `In sync (${formatHours(wl.timeSpentSeconds)})`, existingWorklogId: wl.tempoWorklogId, description: entry.description, activity: entry.activity });
|
|
93
|
+
continue;
|
|
94
|
+
}
|
|
95
|
+
const parts = [];
|
|
96
|
+
if (time)
|
|
97
|
+
parts.push(`${formatHours(wl.timeSpentSeconds)} → ${formatHours(entry.totalSeconds)}`);
|
|
98
|
+
if (text)
|
|
99
|
+
parts.push('text/activity changed');
|
|
100
|
+
if (moved)
|
|
101
|
+
parts.push(`moved to ${wl.startDate} in Tempo → restoring ${entry.date}`);
|
|
102
|
+
plan.push({
|
|
103
|
+
...base,
|
|
104
|
+
action: 'update',
|
|
105
|
+
detail: parts.join('; '),
|
|
106
|
+
existingWorklogId: wl.tempoWorklogId,
|
|
107
|
+
// Session worklogs: text/activity are Tempo-side cosmetics we do not
|
|
108
|
+
// manage — carry the current remote values through the PUT untouched.
|
|
109
|
+
description: entry.kind === 'manual' ? entry.description : wl.description,
|
|
110
|
+
activity: entry.kind === 'manual' ? entry.activity : wl.activity,
|
|
111
|
+
...(remoteChanged(own, wl, entry.date, entry.kind) ? { conflict: true } : {}),
|
|
112
|
+
});
|
|
113
|
+
continue;
|
|
114
|
+
}
|
|
115
|
+
// Ownerless (never pushed) or orphaned (worklog vanished remotely).
|
|
116
|
+
const group = pending.get(`${entry.date}|${jira.issueId}`) ?? { manuals: [], sessions: [] };
|
|
117
|
+
const item = { entry, issueId: jira.issueId, hadOwnership: !!own };
|
|
118
|
+
(entry.kind === 'manual' ? group.manuals : group.sessions).push(item);
|
|
119
|
+
pending.set(`${entry.date}|${jira.issueId}`, group);
|
|
120
|
+
}
|
|
121
|
+
// ── Pass 2: adoption / creation per (date, issue) ──
|
|
122
|
+
for (const [dateIssueKey, group] of pending) {
|
|
123
|
+
const pool = (byDateIssue.get(dateIssueKey) ?? [])
|
|
124
|
+
.filter(w => !accounted.has(w.tempoWorklogId) && !ownedIds.has(w.tempoWorklogId))
|
|
125
|
+
.sort((a, b) => a.tempoWorklogId - b.tempoWorklogId);
|
|
126
|
+
// Manual entries adopt by exact content — an identical unowned worklog
|
|
127
|
+
// IS this entry (either our lost push or the user logging the same thing
|
|
128
|
+
// directly in Tempo); any assignment among equals is semantically equal.
|
|
129
|
+
for (const { entry, issueId, hadOwnership } of [...group.manuals].sort((a, b) => (a.entry.entryId ?? '').localeCompare(b.entry.entryId ?? ''))) {
|
|
130
|
+
const base = {
|
|
131
|
+
date: entry.date, task: entry.task, targetSeconds: entry.totalSeconds,
|
|
132
|
+
issueId, kind: entry.kind, entryId: entry.entryId,
|
|
133
|
+
description: entry.description, activity: entry.activity,
|
|
134
|
+
};
|
|
135
|
+
const idx = pool.findIndex(w => contentMatches(entry, w));
|
|
136
|
+
if (idx !== -1) {
|
|
137
|
+
const wl = pool.splice(idx, 1)[0];
|
|
138
|
+
accounted.add(wl.tempoWorklogId);
|
|
139
|
+
plan.push({ ...base, action: 'update', existingWorklogId: wl.tempoWorklogId, detail: `Re-adopted worklog #${wl.tempoWorklogId}` });
|
|
140
|
+
}
|
|
141
|
+
else {
|
|
142
|
+
plan.push({ ...base, action: 'create', detail: `New (${formatHours(entry.totalSeconds)})`, ...(hadOwnership ? { conflict: true } : {}) });
|
|
143
|
+
}
|
|
144
|
+
}
|
|
145
|
+
// Session aggregate: adopt the single remaining candidate; a multi-way
|
|
146
|
+
// ambiguity is only accepted when the candidates sum to the desired time
|
|
147
|
+
// (a split done in Tempo) — otherwise refuse to guess.
|
|
148
|
+
for (const { entry, issueId, hadOwnership } of group.sessions) {
|
|
149
|
+
const base = {
|
|
150
|
+
date: entry.date, task: entry.task, targetSeconds: entry.totalSeconds,
|
|
151
|
+
issueId, kind: entry.kind,
|
|
152
|
+
};
|
|
153
|
+
if (pool.length === 1) {
|
|
154
|
+
const wl = pool.pop();
|
|
155
|
+
accounted.add(wl.tempoWorklogId);
|
|
156
|
+
const detail = timeDrifts(wl.timeSpentSeconds, entry.totalSeconds)
|
|
157
|
+
? `Re-adopted worklog #${wl.tempoWorklogId}: ${formatHours(wl.timeSpentSeconds)} → ${formatHours(entry.totalSeconds)}`
|
|
158
|
+
: `Re-adopted worklog #${wl.tempoWorklogId}`;
|
|
159
|
+
plan.push({ ...base, action: 'update', existingWorklogId: wl.tempoWorklogId, detail, description: wl.description, activity: wl.activity });
|
|
160
|
+
}
|
|
161
|
+
else if (pool.length > 1) {
|
|
162
|
+
const sum = pool.reduce((s, w) => s + w.timeSpentSeconds, 0);
|
|
163
|
+
const ids = pool.map(w => w.tempoWorklogId);
|
|
164
|
+
for (const w of pool)
|
|
165
|
+
accounted.add(w.tempoWorklogId);
|
|
166
|
+
pool.length = 0;
|
|
167
|
+
if (!timeDrifts(sum, entry.totalSeconds)) {
|
|
168
|
+
plan.push({ ...base, action: 'skip', detail: `Exists in Tempo (${ids.length} worklogs, ${formatHours(sum)})`, extraWorklogIds: ids });
|
|
169
|
+
}
|
|
170
|
+
else {
|
|
171
|
+
plan.push({ ...base, action: 'error', detail: `Ambiguous: ${ids.length} unowned worklogs (${formatHours(sum)}) vs local ${formatHours(entry.totalSeconds)} — resolve in Tempo`, extraWorklogIds: ids });
|
|
172
|
+
}
|
|
173
|
+
}
|
|
174
|
+
else {
|
|
175
|
+
plan.push({ ...base, action: 'create', detail: `New (${formatHours(entry.totalSeconds)})`, ...(hadOwnership ? { conflict: true } : {}) });
|
|
176
|
+
}
|
|
177
|
+
}
|
|
178
|
+
}
|
|
179
|
+
// ── Pass 3: delete propagation ──
|
|
180
|
+
// Strays: ownership keys inside the range whose local line vanished (the
|
|
181
|
+
// user deleted a session / re-tasked a day after pushing) while the worklog
|
|
182
|
+
// still lives in Tempo. Local state is the source of truth — delete, unless
|
|
183
|
+
// the day file itself is missing (that is data loss, not intent).
|
|
184
|
+
if (options.from && options.to) {
|
|
185
|
+
for (const [key, own] of Object.entries(pushLog)) {
|
|
186
|
+
const [kDate, kTask, kManual] = key.split('|');
|
|
187
|
+
if (kDate < options.from || kDate > options.to)
|
|
188
|
+
continue;
|
|
189
|
+
const wl = snapById.get(own.tempoWorklogId);
|
|
190
|
+
if (!wl || accounted.has(wl.tempoWorklogId))
|
|
191
|
+
continue;
|
|
192
|
+
accounted.add(wl.tempoWorklogId);
|
|
193
|
+
const base = {
|
|
194
|
+
date: kDate, task: kTask, targetSeconds: wl.timeSpentSeconds,
|
|
195
|
+
issueId: wl.issueId, existingWorklogId: wl.tempoWorklogId,
|
|
196
|
+
kind: (kManual ? 'manual' : 'session'),
|
|
197
|
+
...(kManual ? { entryId: kManual.slice(2) } : {}),
|
|
198
|
+
};
|
|
199
|
+
if (options.datesWithData?.has(kDate)) {
|
|
200
|
+
plan.push({ ...base, action: 'delete', detail: `Deleted locally → removing from Tempo (${formatHours(wl.timeSpentSeconds)})` });
|
|
201
|
+
}
|
|
202
|
+
else {
|
|
203
|
+
plan.push({ ...base, action: 'skip', detail: `Owned worklog kept — no local data for ${kDate}` });
|
|
204
|
+
}
|
|
205
|
+
}
|
|
206
|
+
}
|
|
207
|
+
// Tombstones: explicit local deletions of pushed manual entries.
|
|
208
|
+
for (const t of tombstones) {
|
|
209
|
+
const wl = snapById.get(t.tempoWorklogId);
|
|
210
|
+
if (!wl || accounted.has(wl.tempoWorklogId))
|
|
211
|
+
continue;
|
|
212
|
+
accounted.add(wl.tempoWorklogId);
|
|
213
|
+
plan.push({
|
|
214
|
+
date: t.date, task: t.task, targetSeconds: wl.timeSpentSeconds,
|
|
215
|
+
issueId: wl.issueId, existingWorklogId: wl.tempoWorklogId,
|
|
216
|
+
kind: 'manual', entryId: t.entryId,
|
|
217
|
+
action: 'delete', detail: `Deleted locally → removing from Tempo (${formatHours(wl.timeSpentSeconds)})`,
|
|
218
|
+
});
|
|
219
|
+
}
|
|
220
|
+
// ── Pass 4: unmatched Tempo worklogs — show, never mutate ──
|
|
221
|
+
for (const wl of tempoWorklogs) {
|
|
222
|
+
if (accounted.has(wl.tempoWorklogId))
|
|
223
|
+
continue;
|
|
224
|
+
let taskKey = `issue:${wl.issueId}`;
|
|
225
|
+
for (const [key, jira] of jiraMap) {
|
|
226
|
+
if (jira.issueId === wl.issueId) {
|
|
227
|
+
taskKey = key;
|
|
228
|
+
break;
|
|
229
|
+
}
|
|
230
|
+
}
|
|
231
|
+
plan.push({
|
|
232
|
+
date: wl.startDate, task: taskKey, targetSeconds: wl.timeSpentSeconds,
|
|
233
|
+
action: 'skip', detail: `Tempo only (${formatHours(wl.timeSpentSeconds)})`,
|
|
234
|
+
existingWorklogId: wl.tempoWorklogId, kind: 'session',
|
|
235
|
+
});
|
|
236
|
+
}
|
|
237
|
+
plan.sort((a, b) => a.date.localeCompare(b.date) || a.task.localeCompare(b.task));
|
|
238
|
+
return plan;
|
|
239
|
+
}
|
|
240
|
+
/**
|
|
241
|
+
* Offline drift check for one day — the status side of the same diff. Works
|
|
242
|
+
* without Jira (ownership keys carry date|task), against a month snapshot.
|
|
243
|
+
* Returns human-readable drift lines; empty array = verified parity.
|
|
244
|
+
*/
|
|
245
|
+
export function computeDayDrift(date, entries, pushLog, snapById, tombstones = []) {
|
|
246
|
+
const drift = [];
|
|
247
|
+
const claimed = new Set();
|
|
248
|
+
for (const entry of entries) {
|
|
249
|
+
const key = pushLogKey(date, entry.task, entry.kind === 'manual' ? entry.entryId : undefined);
|
|
250
|
+
const label = entry.kind === 'manual' ? `${entry.task} (manual)` : entry.task;
|
|
251
|
+
const own = pushLog[key];
|
|
252
|
+
const wl = own ? snapById.get(own.tempoWorklogId) : undefined;
|
|
253
|
+
if (!own || !wl) {
|
|
254
|
+
drift.push(`${label}: not pushed (${formatHours(entry.totalSeconds)})`);
|
|
255
|
+
continue;
|
|
256
|
+
}
|
|
257
|
+
claimed.add(wl.tempoWorklogId);
|
|
258
|
+
// Field-drift lines only — an entry whose remote copy matches the local
|
|
259
|
+
// desired state stays parity even when the push-log baseline is stale.
|
|
260
|
+
const suffix = remoteChanged(own, wl, date, entry.kind) ? ' — edited in Tempo' : '';
|
|
261
|
+
if (wl.startDate !== date) {
|
|
262
|
+
drift.push(`${label}: moved to ${wl.startDate} in Tempo`);
|
|
263
|
+
}
|
|
264
|
+
if (timeDrifts(wl.timeSpentSeconds, entry.totalSeconds)) {
|
|
265
|
+
drift.push(`${label}: ${formatHours(wl.timeSpentSeconds)} in Tempo vs ${formatHours(entry.totalSeconds)} local${suffix}`);
|
|
266
|
+
}
|
|
267
|
+
if (entry.kind === 'manual' && manualTextDrifts(entry, wl)) {
|
|
268
|
+
drift.push(`${label}: description/activity differ${suffix}`);
|
|
269
|
+
}
|
|
270
|
+
}
|
|
271
|
+
// Strays: ownership keys of this date whose local line is gone while the
|
|
272
|
+
// worklog still lives in Tempo — the next push deletes it.
|
|
273
|
+
for (const [key, own] of Object.entries(pushLog)) {
|
|
274
|
+
if (!key.startsWith(`${date}|`))
|
|
275
|
+
continue;
|
|
276
|
+
const wl = snapById.get(own.tempoWorklogId);
|
|
277
|
+
if (!wl || claimed.has(own.tempoWorklogId))
|
|
278
|
+
continue;
|
|
279
|
+
drift.push(`${key.split('|')[1]}: deleted locally, still in Tempo (${formatHours(wl.timeSpentSeconds)})`);
|
|
280
|
+
}
|
|
281
|
+
// Tombstoned manual entries awaiting the delete pass.
|
|
282
|
+
for (const t of tombstones) {
|
|
283
|
+
if (t.date !== date)
|
|
284
|
+
continue;
|
|
285
|
+
const wl = snapById.get(t.tempoWorklogId);
|
|
286
|
+
if (!wl || claimed.has(t.tempoWorklogId))
|
|
287
|
+
continue;
|
|
288
|
+
drift.push(`${t.task}: pending delete in Tempo (${formatHours(wl.timeSpentSeconds)})`);
|
|
289
|
+
}
|
|
290
|
+
return drift;
|
|
291
|
+
}
|
|
292
|
+
//# sourceMappingURL=reconcile.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"reconcile.js","sourceRoot":"","sources":["../../src/push/reconcile.ts"],"names":[],"mappings":"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"}
|
|
@@ -14,6 +14,26 @@ export interface TempoWorkAttribute {
|
|
|
14
14
|
readonly values?: readonly string[];
|
|
15
15
|
readonly names?: Readonly<Record<string, string>>;
|
|
16
16
|
}
|
|
17
|
+
/** Worklog as the /4/worklogs list endpoints return it. */
|
|
18
|
+
export interface RawTempoWorklog {
|
|
19
|
+
readonly tempoWorklogId: number;
|
|
20
|
+
readonly issue?: {
|
|
21
|
+
readonly id: number;
|
|
22
|
+
};
|
|
23
|
+
readonly issueId?: number;
|
|
24
|
+
readonly startDate: string;
|
|
25
|
+
readonly timeSpentSeconds: number;
|
|
26
|
+
readonly description?: string;
|
|
27
|
+
readonly updatedAt?: string;
|
|
28
|
+
readonly attributes?: {
|
|
29
|
+
readonly values?: ReadonlyArray<{
|
|
30
|
+
readonly key: string;
|
|
31
|
+
readonly value: string;
|
|
32
|
+
}>;
|
|
33
|
+
};
|
|
34
|
+
}
|
|
35
|
+
/** Map a raw API worklog to our full snapshot shape (description/activity/updatedAt kept). */
|
|
36
|
+
export declare function mapTempoWorklog(raw: RawTempoWorklog): TempoWorklog;
|
|
17
37
|
/** Tempo HTTP failure with the status preserved — 403 means "scope missing". */
|
|
18
38
|
export declare class TempoApiError extends Error {
|
|
19
39
|
readonly status: number;
|
|
@@ -1,4 +1,17 @@
|
|
|
1
1
|
import { TEMPO_BASE_URL, TEMPO_RATE_LIMIT_MS, ACTIVITY_ATTRIBUTE_KEY, DEFAULT_ACTIVITY } from '../core/constants.js';
|
|
2
|
+
/** Map a raw API worklog to our full snapshot shape (description/activity/updatedAt kept). */
|
|
3
|
+
export function mapTempoWorklog(raw) {
|
|
4
|
+
const activity = raw.attributes?.values?.find(v => v.key === ACTIVITY_ATTRIBUTE_KEY)?.value;
|
|
5
|
+
return {
|
|
6
|
+
tempoWorklogId: raw.tempoWorklogId,
|
|
7
|
+
issueId: raw.issue?.id ?? raw.issueId ?? 0,
|
|
8
|
+
startDate: raw.startDate,
|
|
9
|
+
timeSpentSeconds: raw.timeSpentSeconds,
|
|
10
|
+
...(raw.description !== undefined ? { description: raw.description } : {}),
|
|
11
|
+
...(activity !== undefined ? { activity } : {}),
|
|
12
|
+
...(raw.updatedAt !== undefined ? { updatedAt: raw.updatedAt } : {}),
|
|
13
|
+
};
|
|
14
|
+
}
|
|
2
15
|
/** Tempo HTTP failure with the status preserved — 403 means "scope missing". */
|
|
3
16
|
export class TempoApiError extends Error {
|
|
4
17
|
status;
|
|
@@ -53,16 +66,13 @@ export class TempoClient {
|
|
|
53
66
|
const path = `/4/worklogs/user/${encodeURIComponent(accountId)}`
|
|
54
67
|
+ `?from=${from}&to=${to}&offset=${offset}&limit=${limit}`;
|
|
55
68
|
const response = await this.request('GET', path);
|
|
56
|
-
|
|
57
|
-
|
|
58
|
-
|
|
59
|
-
issueId: wl.issue?.id ?? wl.issueId ?? 0,
|
|
60
|
-
startDate: wl.startDate,
|
|
61
|
-
timeSpentSeconds: wl.timeSpentSeconds,
|
|
62
|
-
});
|
|
69
|
+
const items = response.results ?? [];
|
|
70
|
+
for (const wl of items) {
|
|
71
|
+
allWorklogs.push(mapTempoWorklog(wl));
|
|
63
72
|
}
|
|
64
|
-
|
|
65
|
-
|
|
73
|
+
// metadata.count is the PAGE size, not the total — the only reliable
|
|
74
|
+
// "more pages" signal is metadata.next (verified live 2026-07-07).
|
|
75
|
+
if (!response.metadata?.next || items.length === 0)
|
|
66
76
|
break;
|
|
67
77
|
offset += limit;
|
|
68
78
|
}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"tempo-client.js","sourceRoot":"","sources":["../../src/push/tempo-client.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,cAAc,EAAE,mBAAmB,EAAE,sBAAsB,EAAE,gBAAgB,EAAE,MAAM,sBAAsB,CAAC;
|
|
1
|
+
{"version":3,"file":"tempo-client.js","sourceRoot":"","sources":["../../src/push/tempo-client.ts"],"names":[],"mappings":"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"}
|
|
@@ -1,7 +1,7 @@
|
|
|
1
|
-
import { type AppConfig, type Secrets, type
|
|
1
|
+
import { type AppConfig, type Secrets, type PushPlanEntry, type PushResult, type PushResponse } from '../core/types.js';
|
|
2
2
|
import { TempoClient } from './tempo-client.js';
|
|
3
|
-
|
|
4
|
-
export
|
|
3
|
+
import { buildPushPlan } from './reconcile.js';
|
|
4
|
+
export { buildPushPlan };
|
|
5
5
|
/** Execute mutations from the plan, update push log */
|
|
6
6
|
export declare function executePlan(plan: readonly PushPlanEntry[], tempoClient: TempoClient, accountId: string): Promise<PushResult>;
|
|
7
7
|
interface RunPushOptions {
|
|
@@ -11,7 +11,7 @@ interface RunPushOptions {
|
|
|
11
11
|
readonly config: AppConfig;
|
|
12
12
|
readonly secrets: Secrets;
|
|
13
13
|
readonly filePath?: string;
|
|
14
|
+
readonly force?: boolean;
|
|
14
15
|
}
|
|
15
16
|
/** Full push pipeline: build report → resolve Jira → fetch Tempo → plan → execute */
|
|
16
17
|
export declare function runPush(options: RunPushOptions): Promise<PushResponse>;
|
|
17
|
-
export {};
|