workday-daemon 0.14.0 → 0.17.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/README.md +7 -3
- package/dist/cli.js +190 -83
- package/dist/cli.js.map +1 -1
- package/dist/core/config.d.ts +5 -3
- package/dist/core/config.js +33 -18
- package/dist/core/config.js.map +1 -1
- package/dist/core/constants.d.ts +6 -2
- package/dist/core/constants.js +12 -3
- package/dist/core/constants.js.map +1 -1
- package/dist/core/daily-log.d.ts +16 -12
- package/dist/core/daily-log.js +53 -71
- package/dist/core/daily-log.js.map +1 -1
- package/dist/core/favorites.d.ts +20 -0
- package/dist/core/favorites.js +88 -0
- package/dist/core/favorites.js.map +1 -0
- package/dist/core/janitor.d.ts +1 -0
- package/dist/core/janitor.js +46 -3
- package/dist/core/janitor.js.map +1 -1
- package/dist/core/session-tracker.d.ts +12 -7
- package/dist/core/session-tracker.js +29 -22
- package/dist/core/session-tracker.js.map +1 -1
- package/dist/core/status-renderer.js +3 -5
- package/dist/core/status-renderer.js.map +1 -1
- package/dist/core/types.d.ts +41 -26
- package/dist/core/types.js +5 -0
- package/dist/core/types.js.map +1 -1
- package/dist/daemon.js +12 -15
- package/dist/daemon.js.map +1 -1
- package/dist/http-server.d.ts +11 -1
- package/dist/http-server.js +165 -55
- package/dist/http-server.js.map +1 -1
- package/dist/push/jira-client.d.ts +21 -1
- package/dist/push/jira-client.js +73 -2
- package/dist/push/jira-client.js.map +1 -1
- package/dist/push/report-builder.js +28 -6
- package/dist/push/report-builder.js.map +1 -1
- package/package.json +2 -2
package/dist/core/config.js
CHANGED
|
@@ -58,14 +58,8 @@ export function validateConfig(config) {
|
|
|
58
58
|
if (!config.taskPattern) {
|
|
59
59
|
throw new Error('config.json: taskPattern is required');
|
|
60
60
|
}
|
|
61
|
-
if (!config.
|
|
62
|
-
throw new Error('config.json:
|
|
63
|
-
}
|
|
64
|
-
if (!Number.isInteger(config.schedule.start) || config.schedule.start < 0 || config.schedule.start > 23) {
|
|
65
|
-
throw new Error('config.json: schedule.start must be an integer 0-23');
|
|
66
|
-
}
|
|
67
|
-
if (!Number.isInteger(config.schedule.end) || config.schedule.end < 0 || config.schedule.end > 23) {
|
|
68
|
-
throw new Error('config.json: schedule.end must be an integer 0-23');
|
|
61
|
+
if (!Number.isInteger(config.boundaryHour) || config.boundaryHour < 0 || config.boundaryHour > 23) {
|
|
62
|
+
throw new Error('config.json: boundaryHour must be an integer 0-23');
|
|
69
63
|
}
|
|
70
64
|
if (!isValidTimezone(config.timezone)) {
|
|
71
65
|
throw new Error(`config.json: invalid timezone "${config.timezone}"`);
|
|
@@ -119,11 +113,19 @@ export function loadConfig() {
|
|
|
119
113
|
}
|
|
120
114
|
const raw = readJson(configPath);
|
|
121
115
|
const systemTimezone = Intl.DateTimeFormat().resolvedOptions().timeZone;
|
|
122
|
-
// Backward compat:
|
|
123
|
-
|
|
124
|
-
|
|
125
|
-
|
|
116
|
+
// Backward compat: schedule {start,end} → boundaryHour (start was never
|
|
117
|
+
// read by any algorithm), and the even older dayBoundaryHour.
|
|
118
|
+
if (raw.boundaryHour === undefined) {
|
|
119
|
+
const schedule = raw.schedule;
|
|
120
|
+
if (typeof schedule?.end === 'number') {
|
|
121
|
+
raw.boundaryHour = schedule.end;
|
|
122
|
+
}
|
|
123
|
+
else if (typeof raw.dayBoundaryHour === 'number') {
|
|
124
|
+
raw.boundaryHour = raw.dayBoundaryHour;
|
|
125
|
+
}
|
|
126
126
|
}
|
|
127
|
+
delete raw.schedule;
|
|
128
|
+
delete raw.dayBoundaryHour;
|
|
127
129
|
const rawSensitivity = (raw.sensitivity ?? {});
|
|
128
130
|
const sensitivity = {
|
|
129
131
|
default: rawSensitivity.default ?? DEFAULT_SENSITIVITY,
|
|
@@ -132,7 +134,7 @@ export function loadConfig() {
|
|
|
132
134
|
const rawSession = (raw.session ?? {});
|
|
133
135
|
const config = {
|
|
134
136
|
...raw,
|
|
135
|
-
|
|
137
|
+
boundaryHour: raw.boundaryHour ?? 4,
|
|
136
138
|
apiPort: raw.apiPort ?? DEFAULT_API_PORT,
|
|
137
139
|
timezone: raw.timezone ?? systemTimezone,
|
|
138
140
|
sensitivity,
|
|
@@ -166,7 +168,6 @@ export function buildPatchedConfig(current, patch) {
|
|
|
166
168
|
const merged = {
|
|
167
169
|
...current,
|
|
168
170
|
...patch,
|
|
169
|
-
schedule: { ...current.schedule, ...(patch.schedule ?? {}) },
|
|
170
171
|
sensitivity: {
|
|
171
172
|
default: patch.sensitivity?.default ?? current.sensitivity.default,
|
|
172
173
|
perRepo: patch.sensitivity?.perRepo ?? current.sensitivity.perRepo,
|
|
@@ -209,6 +210,20 @@ export function loadSecrets() {
|
|
|
209
210
|
validateSecrets(secrets);
|
|
210
211
|
return secrets;
|
|
211
212
|
}
|
|
213
|
+
/** Non-fatal variant for optional integrations: missing/invalid → null. */
|
|
214
|
+
export function tryLoadSecrets() {
|
|
215
|
+
const secretsPath = join(WORKDAY_HOME, SECRETS_FILE_NAME);
|
|
216
|
+
if (!existsSync(secretsPath))
|
|
217
|
+
return null;
|
|
218
|
+
try {
|
|
219
|
+
const secrets = readJson(secretsPath);
|
|
220
|
+
validateSecrets(secrets);
|
|
221
|
+
return secrets;
|
|
222
|
+
}
|
|
223
|
+
catch {
|
|
224
|
+
return null;
|
|
225
|
+
}
|
|
226
|
+
}
|
|
212
227
|
export function getWorkdayHome() {
|
|
213
228
|
return WORKDAY_HOME;
|
|
214
229
|
}
|
|
@@ -249,12 +264,12 @@ export function formatDate(timestamp, timezone) {
|
|
|
249
264
|
}
|
|
250
265
|
/**
|
|
251
266
|
* Compute working date in the configured timezone.
|
|
252
|
-
* If current hour <
|
|
253
|
-
*
|
|
267
|
+
* If current hour < boundaryHour, attribute activity to previous calendar day.
|
|
268
|
+
* boundaryHour is 24h format (e.g. 4 = 04:00 AM).
|
|
254
269
|
*/
|
|
255
|
-
export function computeWorkingDate(timestamp,
|
|
270
|
+
export function computeWorkingDate(timestamp, boundaryHour, timezone) {
|
|
256
271
|
const hour = getHourInTimezone(timestamp, timezone);
|
|
257
|
-
if (hour <
|
|
272
|
+
if (hour < boundaryHour) {
|
|
258
273
|
return formatDate(timestamp - 86_400_000, timezone);
|
|
259
274
|
}
|
|
260
275
|
return formatDate(timestamp, timezone);
|
package/dist/core/config.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"config.js","sourceRoot":"","sources":["../../src/core/config.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,YAAY,EAAE,UAAU,EAAE,aAAa,EAAE,UAAU,EAAE,MAAM,SAAS,CAAC;AAC9E,OAAO,EAAE,IAAI,EAAE,OAAO,EAAE,QAAQ,EAAE,MAAM,WAAW,CAAC;AACpD,OAAO,EAAE,OAAO,EAAE,MAAM,SAAS,CAAC;AAClC,OAAO,EAAE,aAAa,EAAE,MAAM,UAAU,CAAC;AAEzC,OAAO,EAAE,gBAAgB,EAAE,MAAM,YAAY,CAAC;AAC9C,OAAO,EAAE,gBAAgB,EAAE,iBAAiB,EAAE,aAAa,EAAE,gBAAgB,EAAE,wBAAwB,EAAE,mBAAmB,EAAE,oBAAoB,EAAE,aAAa,EAAE,MAAM,gBAAgB,CAAC;AAE1L,gEAAgE;AAChE,SAAS,eAAe;IACtB,IAAI,GAAG,GAAG,OAAO,CAAC,aAAa,CAAC,MAAM,CAAC,IAAI,CAAC,GAAG,CAAC,CAAC,CAAC;IAClD,OAAO,GAAG,KAAK,OAAO,CAAC,GAAG,CAAC,EAAE,CAAC;QAC5B,IAAI,UAAU,CAAC,IAAI,CAAC,GAAG,EAAE,cAAc,CAAC,CAAC;YAAE,OAAO,GAAG,CAAC;QACtD,GAAG,GAAG,OAAO,CAAC,GAAG,CAAC,CAAC;IACrB,CAAC;IACD,MAAM,IAAI,KAAK,CAAC,qDAAqD,CAAC,CAAC;AACzE,CAAC;AAED;;;;;GAKG;AACH,SAAS,kBAAkB;IACzB,IAAI,OAAO,CAAC,GAAG,CAAC,YAAY;QAAE,OAAO,OAAO,CAAC,GAAG,CAAC,YAAY,CAAC;IAC9D,MAAM,OAAO,GAAG,eAAe,EAAE,CAAC;IAClC,IAAI,UAAU,CAAC,IAAI,CAAC,OAAO,EAAE,gBAAgB,CAAC,CAAC;QAAE,OAAO,OAAO,CAAC;IAChE,OAAO,IAAI,CAAC,OAAO,EAAE,EAAE,UAAU,CAAC,CAAC;AACrC,CAAC;AAED,MAAM,YAAY,GAAG,eAAe,EAAE,CAAC;AACvC,MAAM,YAAY,GAAG,kBAAkB,EAAE,CAAC;AAE1C,SAAS,QAAQ,CAAI,QAAgB;IACnC,IAAI,CAAC,UAAU,CAAC,QAAQ,CAAC,EAAE,CAAC;QAC1B,MAAM,IAAI,KAAK,CAAC,mBAAmB,QAAQ,EAAE,CAAC,CAAC;IACjD,CAAC;IACD,MAAM,GAAG,GAAG,YAAY,CAAC,QAAQ,EAAE,OAAO,CAAC,CAAC;IAC5C,OAAO,IAAI,CAAC,KAAK,CAAC,GAAG,CAAM,CAAC;AAC9B,CAAC;AAED,SAAS,eAAe,CAAC,EAAU;IACjC,IAAI,CAAC;QACH,IAAI,CAAC,cAAc,CAAC,SAAS,EAAE,EAAE,QAAQ,EAAE,EAAE,EAAE,CAAC,CAAC;QACjD,OAAO,IAAI,CAAC;IACd,CAAC;IAAC,MAAM,CAAC;QACP,OAAO,KAAK,CAAC;IACf,CAAC;AACH,CAAC;AAED,MAAM,UAAU,cAAc,CAAC,MAAiB;IAC9C,IAAI,CAAC,MAAM,CAAC,KAAK,IAAI,MAAM,CAAC,KAAK,CAAC,MAAM,KAAK,CAAC,EAAE,CAAC;QAC/C,MAAM,IAAI,KAAK,CAAC,8CAA8C,CAAC,CAAC;IAClE,CAAC;IAED,KAAK,MAAM,IAAI,IAAI,MAAM,CAAC,KAAK,EAAE,CAAC;QAChC,IAAI,CAAC,UAAU,CAAC,IAAI,CAAC,EAAE,CAAC;YACtB,OAAO,CAAC,IAAI,CAAC,iCAAiC,IAAI,EAAE,CAAC,CAAC;QACxD,CAAC;IACH,CAAC;IAED,IAAI,CAAC,MAAM,CAAC,WAAW,EAAE,CAAC;QACxB,MAAM,IAAI,KAAK,CAAC,sCAAsC,CAAC,CAAC;IAC1D,CAAC;IAED,IAAI,CAAC,MAAM,CAAC,
|
|
1
|
+
{"version":3,"file":"config.js","sourceRoot":"","sources":["../../src/core/config.ts"],"names":[],"mappings":"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"}
|
package/dist/core/constants.d.ts
CHANGED
|
@@ -2,13 +2,14 @@ export declare const CONFIG_FILE_NAME = "config.json";
|
|
|
2
2
|
export declare const SECRETS_FILE_NAME = "secrets.json";
|
|
3
3
|
export declare const PID_FILE_NAME = "workday.pid";
|
|
4
4
|
export declare const STOP_MARKER_FILE_NAME = "daemon.stopped";
|
|
5
|
+
export declare const FAVORITES_FILE_NAME = "favorites.json";
|
|
5
6
|
export declare const DATA_DIR_NAME = "data";
|
|
6
7
|
export declare const TMP_EXTENSION = ".tmp";
|
|
7
8
|
export declare const BACKUP_EXTENSION = ".bak";
|
|
8
9
|
export declare const DAEMON_SCRIPT_TS = "daemon.ts";
|
|
9
10
|
export declare const DAEMON_SCRIPT_JS = "daemon.js";
|
|
10
11
|
export declare const DEFAULT_API_PORT = 9213;
|
|
11
|
-
export declare const API_VERSION =
|
|
12
|
+
export declare const API_VERSION = 9;
|
|
12
13
|
export declare const NPM_PACKAGE_NAME = "workday-daemon";
|
|
13
14
|
export declare const NPM_REGISTRY_LATEST_URL = "https://registry.npmjs.org/workday-daemon/latest";
|
|
14
15
|
/** Registry check timeout — fail fast, the next scheduled check will retry */
|
|
@@ -23,7 +24,7 @@ export declare const LOCK_EXTENSION = ".lock";
|
|
|
23
24
|
export declare const LOCK_STALE_MS = 10000;
|
|
24
25
|
export declare const GIT_BATCH_SEPARATOR = "---WORKDAY-SEP---";
|
|
25
26
|
export declare const GIT_MAX_BUFFER_BYTES: number;
|
|
26
|
-
export declare const
|
|
27
|
+
export declare const MAX_ENTRY_MINUTES = 480;
|
|
27
28
|
export declare const ACTIVITY_ATTRIBUTE_KEY = "_Activity_";
|
|
28
29
|
export declare const DEFAULT_ACTIVITY = "Development";
|
|
29
30
|
export declare const DEFAULT_MANUAL_ACTIVITY = "Other";
|
|
@@ -32,6 +33,9 @@ export declare const FALLBACK_ACTIVITIES: ReadonlyArray<{
|
|
|
32
33
|
readonly value: string;
|
|
33
34
|
readonly name: string;
|
|
34
35
|
}>;
|
|
36
|
+
export declare const JIRA_SEARCH_MIN_QUERY_LENGTH = 2;
|
|
37
|
+
export declare const JIRA_SEARCH_CACHE_TTL_MS: number;
|
|
38
|
+
export declare const JIRA_SEARCH_CACHE_MAX_ENTRIES = 50;
|
|
35
39
|
export declare const ISSUE_CACHE_FILE = "issue-cache.json";
|
|
36
40
|
export declare const PUSH_LOG_FILE = "push-log.json";
|
|
37
41
|
export declare const TEMPO_REPORT_DIR = "tempo";
|
package/dist/core/constants.js
CHANGED
|
@@ -5,6 +5,7 @@ export const PID_FILE_NAME = 'workday.pid';
|
|
|
5
5
|
// Manual-stop marker (in WORKDAY_HOME) — the tray watchdog does not respawn
|
|
6
6
|
// a manually stopped daemon; cleared on daemon start / autostart login.
|
|
7
7
|
export const STOP_MARKER_FILE_NAME = 'daemon.stopped';
|
|
8
|
+
export const FAVORITES_FILE_NAME = 'favorites.json';
|
|
8
9
|
export const DATA_DIR_NAME = 'data';
|
|
9
10
|
export const TMP_EXTENSION = '.tmp';
|
|
10
11
|
export const BACKUP_EXTENSION = '.bak';
|
|
@@ -18,7 +19,7 @@ export const DEFAULT_API_PORT = 9213;
|
|
|
18
19
|
// pick it up (they re-check every 6h), THEN npm-publish the daemon —
|
|
19
20
|
// a tray with the old exact-match check meeting a newer apiVersion would
|
|
20
21
|
// reinstall-loop the daemon.
|
|
21
|
-
export const API_VERSION =
|
|
22
|
+
export const API_VERSION = 9;
|
|
22
23
|
// ─── Auto-update ────────────────────────────────────────────────────────
|
|
23
24
|
export const NPM_PACKAGE_NAME = 'workday-daemon';
|
|
24
25
|
export const NPM_REGISTRY_LATEST_URL = `https://registry.npmjs.org/${NPM_PACKAGE_NAME}/latest`;
|
|
@@ -36,8 +37,8 @@ export const LOCK_STALE_MS = 10_000;
|
|
|
36
37
|
// ─── Git internals ──────────────────────────────────────────────────────
|
|
37
38
|
export const GIT_BATCH_SEPARATOR = '---WORKDAY-SEP---';
|
|
38
39
|
export const GIT_MAX_BUFFER_BYTES = 10 * 1024 * 1024;
|
|
39
|
-
// ───
|
|
40
|
-
export const
|
|
40
|
+
// ─── Manual entry cap (per-item typo guard) ─────────────────────────────
|
|
41
|
+
export const MAX_ENTRY_MINUTES = 480;
|
|
41
42
|
// ─── Manual entry / Activity types ──────────────────────────────────────
|
|
42
43
|
export const ACTIVITY_ATTRIBUTE_KEY = '_Activity_';
|
|
43
44
|
export const DEFAULT_ACTIVITY = 'Development'; // sessions (value == name)
|
|
@@ -64,6 +65,14 @@ export const FALLBACK_ACTIVITIES = [
|
|
|
64
65
|
{ value: 'Testing', name: 'Testing' },
|
|
65
66
|
{ value: 'TestReview', name: 'Test Review' },
|
|
66
67
|
];
|
|
68
|
+
// ─── Jira search (log-cloud live fallback) ──────────────────────────────
|
|
69
|
+
// Queries shorter than this return empty without hitting Jira (mirrors the
|
|
70
|
+
// tray's len>=2 debounce rule).
|
|
71
|
+
export const JIRA_SEARCH_MIN_QUERY_LENGTH = 2;
|
|
72
|
+
// In-memory cache of recent search queries — results are perishable, never
|
|
73
|
+
// persisted to disk.
|
|
74
|
+
export const JIRA_SEARCH_CACHE_TTL_MS = 5 * 60_000;
|
|
75
|
+
export const JIRA_SEARCH_CACHE_MAX_ENTRIES = 50;
|
|
67
76
|
// ─── Push / Tempo ───────────────────────────────────────────────────────
|
|
68
77
|
export const ISSUE_CACHE_FILE = 'issue-cache.json';
|
|
69
78
|
export const PUSH_LOG_FILE = 'push-log.json';
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"constants.js","sourceRoot":"","sources":["../../src/core/constants.ts"],"names":[],"mappings":"AAAA,2EAA2E;AAC3E,MAAM,CAAC,MAAM,gBAAgB,GAAG,aAAa,CAAC;AAC9C,MAAM,CAAC,MAAM,iBAAiB,GAAG,cAAc,CAAC;AAChD,MAAM,CAAC,MAAM,aAAa,GAAG,aAAa,CAAC;AAC3C,4EAA4E;AAC5E,wEAAwE;AACxE,MAAM,CAAC,MAAM,qBAAqB,GAAG,gBAAgB,CAAC;AACtD,MAAM,CAAC,MAAM,aAAa,GAAG,MAAM,CAAC;AACpC,MAAM,CAAC,MAAM,aAAa,GAAG,MAAM,CAAC;AACpC,MAAM,CAAC,MAAM,gBAAgB,GAAG,MAAM,CAAC;AAEvC,2EAA2E;AAC3E,MAAM,CAAC,MAAM,gBAAgB,GAAG,WAAW,CAAC;AAC5C,MAAM,CAAC,MAAM,gBAAgB,GAAG,WAAW,CAAC;AAE5C,0EAA0E;AAC1E,MAAM,CAAC,MAAM,gBAAgB,GAAG,IAAI,CAAC;AACrC,6EAA6E;AAC7E,yEAAyE;AACzE,qEAAqE;AACrE,yEAAyE;AACzE,6BAA6B;AAC7B,MAAM,CAAC,MAAM,WAAW,GAAG,CAAC,CAAC;AAE7B,2EAA2E;AAC3E,MAAM,CAAC,MAAM,gBAAgB,GAAG,gBAAgB,CAAC;AACjD,MAAM,CAAC,MAAM,uBAAuB,GAAG,8BAA8B,gBAAgB,SAAS,CAAC;AAC/F,8EAA8E;AAC9E,MAAM,CAAC,MAAM,uBAAuB,GAAG,KAAK,CAAC;AAC7C,4EAA4E;AAC5E,MAAM,CAAC,MAAM,sBAAsB,GAAG,OAAO,CAAC;AAC9C,yEAAyE;AACzE,MAAM,CAAC,MAAM,2BAA2B,GAAG,CAAC,CAAC;AAC7C,sFAAsF;AACtF,MAAM,CAAC,MAAM,2BAA2B,GAAG,EAAE,CAAC;AAE9C,0EAA0E;AAC1E,MAAM,CAAC,MAAM,cAAc,GAAG,OAAO,CAAC;AACtC,MAAM,CAAC,MAAM,aAAa,GAAG,MAAM,CAAC;AAEpC,2EAA2E;AAC3E,MAAM,CAAC,MAAM,mBAAmB,GAAG,mBAAmB,CAAC;AACvD,MAAM,CAAC,MAAM,oBAAoB,GAAG,EAAE,GAAG,IAAI,GAAG,IAAI,CAAC;AAErD,2EAA2E;AAC3E,MAAM,CAAC,MAAM,
|
|
1
|
+
{"version":3,"file":"constants.js","sourceRoot":"","sources":["../../src/core/constants.ts"],"names":[],"mappings":"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"}
|
package/dist/core/daily-log.d.ts
CHANGED
|
@@ -53,10 +53,6 @@ export declare function computeDaySummary(sessions: readonly Session[]): {
|
|
|
53
53
|
};
|
|
54
54
|
/** Resolve session by 1-based index or hex id */
|
|
55
55
|
export declare function resolveSessionTarget(log: DailyLog, target: string): Session | null;
|
|
56
|
-
/** Sum of manual adjustment minutes for a session */
|
|
57
|
-
export declare function computeManualMinutes(session: Session): number;
|
|
58
|
-
/** Effective duration including manual adjustments (ms) */
|
|
59
|
-
export declare function computeFullEffectiveDuration(session: Session): number;
|
|
60
56
|
/**
|
|
61
57
|
* UI-only resolver for the day-start indicator. Returns null when no session
|
|
62
58
|
* has reached ACTIVE yet, so the client hides the indicator until then.
|
|
@@ -71,36 +67,38 @@ export declare function resolveUiDayStart(log: DailyLog): string | null;
|
|
|
71
67
|
export declare function computeDayEnd(date: string, dayBoundaryHour: number, timezone: string): number;
|
|
72
68
|
/**
|
|
73
69
|
* Budget v2: the full physical day window (boundary hour → next boundary
|
|
74
|
-
* hour, ~24h). Depends only on log.date and config — never on sessions
|
|
75
|
-
*
|
|
70
|
+
* hour, ~24h). Depends only on log.date and config — never on sessions or
|
|
71
|
+
* the daemon lifecycle, so restarts mid-day don't shrink it.
|
|
76
72
|
* On DST transition days the window is honestly 23/25h — the physical day
|
|
77
73
|
* length, not a bug.
|
|
78
74
|
*/
|
|
79
75
|
export declare function computeBudgetMs(log: DailyLog, config: AppConfig): number;
|
|
80
76
|
/** Sum of all manual entries' minutes (ms) */
|
|
81
77
|
export declare function computeTotalManualEntryMs(log: DailyLog): number;
|
|
82
|
-
/** Sum of all sessions'
|
|
78
|
+
/** Sum of all sessions' observed duration + manual entries (ms) */
|
|
83
79
|
export declare function computeTotalClaimedMs(log: DailyLog): number;
|
|
84
80
|
/** Remaining budget in ms, clamped >= 0 */
|
|
85
81
|
export declare function getRemainingBudgetMs(log: DailyLog, config: AppConfig): number;
|
|
86
82
|
/** Compute per-session active intervals (pauses excluded, no cross-session merge). */
|
|
87
83
|
export declare function computeActiveIntervals(sessions: readonly Session[]): ActiveInterval[];
|
|
88
|
-
/** Add manual adjustment to a session. Throws on validation failure. */
|
|
89
|
-
export declare function addManualAdjustment(log: DailyLog, sessionId: string, minutes: number, reason: string, config: AppConfig): void;
|
|
90
84
|
/** Find a manual entry by id */
|
|
91
85
|
export declare function findManualEntry(log: DailyLog, id: string): ManualEntry | undefined;
|
|
92
86
|
/** Resolve a manual entry by 1-based index (#2) or id */
|
|
93
87
|
export declare function resolveManualEntryTarget(log: DailyLog, target: string): ManualEntry | null;
|
|
88
|
+
/** Validate a task key against the configured pattern (full-string match). */
|
|
89
|
+
export declare function assertValidTask(task: string, config: AppConfig): void;
|
|
94
90
|
/**
|
|
95
|
-
* Add a manual entry —
|
|
96
|
-
*
|
|
97
|
-
*
|
|
91
|
+
* Add a manual entry — declared time on a task. Session-born entries
|
|
92
|
+
* (sourceSessionId set) have no description and are always Development;
|
|
93
|
+
* standalone entries require description and activity.
|
|
94
|
+
* Budget invariant: total claimed ≤ day window. Throws on validation failure.
|
|
98
95
|
*/
|
|
99
96
|
export declare function addManualEntry(log: DailyLog, input: {
|
|
100
97
|
task: string;
|
|
101
98
|
minutes: number;
|
|
102
99
|
description: string;
|
|
103
100
|
activity: string;
|
|
101
|
+
sourceSessionId?: string;
|
|
104
102
|
}, config: AppConfig): ManualEntry;
|
|
105
103
|
/**
|
|
106
104
|
* Edit a manual entry in place (absolute set of provided fields).
|
|
@@ -111,5 +109,11 @@ export declare function editManualEntry(log: DailyLog, id: string, patch: {
|
|
|
111
109
|
description?: string;
|
|
112
110
|
activity?: string;
|
|
113
111
|
}, config: AppConfig): void;
|
|
112
|
+
/**
|
|
113
|
+
* Delete a manual entry. Session-born entries are deletable too (unlike
|
|
114
|
+
* edit) — removing one just un-claims the extra session time. Throws when
|
|
115
|
+
* the id is unknown.
|
|
116
|
+
*/
|
|
117
|
+
export declare function deleteManualEntry(log: DailyLog, id: string): ManualEntry;
|
|
114
118
|
/** Add signal with deduplication for diff_dynamics (same repo, accumulate deltas) */
|
|
115
119
|
export declare function addSignal(log: DailyLog, signal: Signal, deduplicationSeconds: number): void;
|
package/dist/core/daily-log.js
CHANGED
|
@@ -3,7 +3,7 @@ import { join, dirname } from 'node:path';
|
|
|
3
3
|
import { randomBytes } from 'node:crypto';
|
|
4
4
|
import { getDataDir, computeWorkingDate } from './config.js';
|
|
5
5
|
import { DayStatus, DayType, SignalType } from './types.js';
|
|
6
|
-
import { TMP_EXTENSION, BACKUP_EXTENSION, LOCK_EXTENSION, LOCK_STALE_MS,
|
|
6
|
+
import { TMP_EXTENSION, BACKUP_EXTENSION, LOCK_EXTENSION, LOCK_STALE_MS, MAX_ENTRY_MINUTES, MS_PER_MINUTE, DEFAULT_ACTIVITY } from './constants.js';
|
|
7
7
|
/** Generate short unique session id */
|
|
8
8
|
export function generateSessionId() {
|
|
9
9
|
return randomBytes(4).toString('hex');
|
|
@@ -43,7 +43,6 @@ export function createEmptyLog(date, config) {
|
|
|
43
43
|
date,
|
|
44
44
|
status: DayStatus.Draft,
|
|
45
45
|
dayType: determineDayType(date, config),
|
|
46
|
-
dayStartedAt: null,
|
|
47
46
|
sessions: [],
|
|
48
47
|
signals: [],
|
|
49
48
|
manualEntries: [],
|
|
@@ -211,7 +210,7 @@ export function deleteDailyLog(date) {
|
|
|
211
210
|
}
|
|
212
211
|
/** Get or create today's daily log */
|
|
213
212
|
export function getOrCreateTodayLog(config) {
|
|
214
|
-
const today = computeWorkingDate(Date.now(), config.
|
|
213
|
+
const today = computeWorkingDate(Date.now(), config.boundaryHour, config.timezone);
|
|
215
214
|
const existing = readDailyLog(today);
|
|
216
215
|
if (existing) {
|
|
217
216
|
return existing;
|
|
@@ -334,16 +333,6 @@ export function resolveSessionTarget(log, target) {
|
|
|
334
333
|
return log.sessions.find(s => s.id === target) ?? null;
|
|
335
334
|
}
|
|
336
335
|
// ─── Budget computation ─────────────────────────────────────────────────
|
|
337
|
-
/** Sum of manual adjustment minutes for a session */
|
|
338
|
-
export function computeManualMinutes(session) {
|
|
339
|
-
if (!session.manualAdjustments || session.manualAdjustments.length === 0)
|
|
340
|
-
return 0;
|
|
341
|
-
return session.manualAdjustments.reduce((sum, a) => sum + a.minutes, 0);
|
|
342
|
-
}
|
|
343
|
-
/** Effective duration including manual adjustments (ms) */
|
|
344
|
-
export function computeFullEffectiveDuration(session) {
|
|
345
|
-
return computeEffectiveDuration(session) + computeManualMinutes(session) * MS_PER_MINUTE;
|
|
346
|
-
}
|
|
347
336
|
/**
|
|
348
337
|
* UI-only resolver for the day-start indicator. Returns null when no session
|
|
349
338
|
* has reached ACTIVE yet, so the client hides the indicator until then.
|
|
@@ -374,23 +363,23 @@ export function computeDayEnd(date, dayBoundaryHour, timezone) {
|
|
|
374
363
|
}
|
|
375
364
|
/**
|
|
376
365
|
* Budget v2: the full physical day window (boundary hour → next boundary
|
|
377
|
-
* hour, ~24h). Depends only on log.date and config — never on sessions
|
|
378
|
-
*
|
|
366
|
+
* hour, ~24h). Depends only on log.date and config — never on sessions or
|
|
367
|
+
* the daemon lifecycle, so restarts mid-day don't shrink it.
|
|
379
368
|
* On DST transition days the window is honestly 23/25h — the physical day
|
|
380
369
|
* length, not a bug.
|
|
381
370
|
*/
|
|
382
371
|
export function computeBudgetMs(log, config) {
|
|
383
|
-
const dayStart = parseDateWithHour(log.date, config.
|
|
384
|
-
const dayEnd = computeDayEnd(log.date, config.
|
|
372
|
+
const dayStart = parseDateWithHour(log.date, config.boundaryHour, config.timezone);
|
|
373
|
+
const dayEnd = computeDayEnd(log.date, config.boundaryHour, config.timezone);
|
|
385
374
|
return Math.max(0, dayEnd - dayStart);
|
|
386
375
|
}
|
|
387
376
|
/** Sum of all manual entries' minutes (ms) */
|
|
388
377
|
export function computeTotalManualEntryMs(log) {
|
|
389
378
|
return (log.manualEntries ?? []).reduce((sum, e) => sum + e.minutes * MS_PER_MINUTE, 0);
|
|
390
379
|
}
|
|
391
|
-
/** Sum of all sessions'
|
|
380
|
+
/** Sum of all sessions' observed duration + manual entries (ms) */
|
|
392
381
|
export function computeTotalClaimedMs(log) {
|
|
393
|
-
const sessionsMs = log.sessions.reduce((sum, s) => sum +
|
|
382
|
+
const sessionsMs = log.sessions.reduce((sum, s) => sum + computeEffectiveDuration(s), 0);
|
|
394
383
|
return sessionsMs + computeTotalManualEntryMs(log);
|
|
395
384
|
}
|
|
396
385
|
/** Remaining budget in ms, clamped >= 0 */
|
|
@@ -440,36 +429,6 @@ function unsealForEdit(log) {
|
|
|
440
429
|
log.status = DayStatus.Draft;
|
|
441
430
|
}
|
|
442
431
|
}
|
|
443
|
-
/** Add manual adjustment to a session. Throws on validation failure. */
|
|
444
|
-
export function addManualAdjustment(log, sessionId, minutes, reason, config) {
|
|
445
|
-
const session = log.sessions.find(s => s.id === sessionId);
|
|
446
|
-
if (!session) {
|
|
447
|
-
throw new Error(`Session not found: ${sessionId}`);
|
|
448
|
-
}
|
|
449
|
-
if (minutes <= 0) {
|
|
450
|
-
throw new Error('Minutes must be positive');
|
|
451
|
-
}
|
|
452
|
-
if (minutes > MAX_ADJUSTMENT_MINUTES) {
|
|
453
|
-
throw new Error(`Max adjustment is ${MAX_ADJUSTMENT_MINUTES} minutes (8h)`);
|
|
454
|
-
}
|
|
455
|
-
// Check budget
|
|
456
|
-
const currentClaimed = computeTotalClaimedMs(log);
|
|
457
|
-
const addMs = minutes * MS_PER_MINUTE;
|
|
458
|
-
const budget = computeBudgetMs(log, config);
|
|
459
|
-
if (currentClaimed + addMs > budget) {
|
|
460
|
-
const remainMinutes = Math.floor(getRemainingBudgetMs(log, config) / MS_PER_MINUTE);
|
|
461
|
-
throw new Error(`Exceeds 24h day window. Remaining: ${remainMinutes}m.`);
|
|
462
|
-
}
|
|
463
|
-
if (!session.manualAdjustments) {
|
|
464
|
-
session.manualAdjustments = [];
|
|
465
|
-
}
|
|
466
|
-
unsealForEdit(log);
|
|
467
|
-
session.manualAdjustments.push({
|
|
468
|
-
minutes,
|
|
469
|
-
reason,
|
|
470
|
-
addedAt: new Date().toISOString(),
|
|
471
|
-
});
|
|
472
|
-
}
|
|
473
432
|
// ─── Manual entries ───────────────────────────────────────────────────────
|
|
474
433
|
/** Find a manual entry by id */
|
|
475
434
|
export function findManualEntry(log, id) {
|
|
@@ -485,16 +444,17 @@ export function resolveManualEntryTarget(log, target) {
|
|
|
485
444
|
return entries.find(e => e.id === target) ?? null;
|
|
486
445
|
}
|
|
487
446
|
/** Validate a task key against the configured pattern (full-string match). */
|
|
488
|
-
function assertValidTask(task, config) {
|
|
447
|
+
export function assertValidTask(task, config) {
|
|
489
448
|
const match = task.match(new RegExp(config.taskPattern));
|
|
490
449
|
if (!match || match[0] !== task) {
|
|
491
450
|
throw new Error(`Task "${task}" is not a valid key (pattern: ${config.taskPattern})`);
|
|
492
451
|
}
|
|
493
452
|
}
|
|
494
453
|
/**
|
|
495
|
-
* Add a manual entry —
|
|
496
|
-
*
|
|
497
|
-
*
|
|
454
|
+
* Add a manual entry — declared time on a task. Session-born entries
|
|
455
|
+
* (sourceSessionId set) have no description and are always Development;
|
|
456
|
+
* standalone entries require description and activity.
|
|
457
|
+
* Budget invariant: total claimed ≤ day window. Throws on validation failure.
|
|
498
458
|
*/
|
|
499
459
|
export function addManualEntry(log, input, config) {
|
|
500
460
|
const task = input.task.trim();
|
|
@@ -504,15 +464,18 @@ export function addManualEntry(log, input, config) {
|
|
|
504
464
|
if (!Number.isFinite(input.minutes) || input.minutes <= 0) {
|
|
505
465
|
throw new Error('Minutes must be positive');
|
|
506
466
|
}
|
|
507
|
-
if (input.minutes >
|
|
508
|
-
throw new Error(`Max is ${
|
|
467
|
+
if (input.minutes > MAX_ENTRY_MINUTES) {
|
|
468
|
+
throw new Error(`Max is ${MAX_ENTRY_MINUTES} minutes (8h)`);
|
|
509
469
|
}
|
|
510
|
-
const
|
|
511
|
-
|
|
512
|
-
throw new Error('Description is required');
|
|
513
|
-
const activity = input.activity.trim();
|
|
470
|
+
const sessionBorn = !!input.sourceSessionId;
|
|
471
|
+
const activity = sessionBorn ? DEFAULT_ACTIVITY : input.activity.trim();
|
|
514
472
|
if (!activity)
|
|
515
473
|
throw new Error('Activity is required');
|
|
474
|
+
// Description is user data; only Development entries may leave it empty.
|
|
475
|
+
const description = sessionBorn ? '' : input.description.trim();
|
|
476
|
+
if (!sessionBorn && !description && activity !== DEFAULT_ACTIVITY) {
|
|
477
|
+
throw new Error('Description is required (only Development may omit it)');
|
|
478
|
+
}
|
|
516
479
|
const addMs = input.minutes * MS_PER_MINUTE;
|
|
517
480
|
if (computeTotalClaimedMs(log) + addMs > computeBudgetMs(log, config)) {
|
|
518
481
|
const remainMinutes = Math.floor(getRemainingBudgetMs(log, config) / MS_PER_MINUTE);
|
|
@@ -528,6 +491,7 @@ export function addManualEntry(log, input, config) {
|
|
|
528
491
|
description,
|
|
529
492
|
activity,
|
|
530
493
|
createdAt: new Date().toISOString(),
|
|
494
|
+
...(sessionBorn ? { sourceSessionId: input.sourceSessionId } : {}),
|
|
531
495
|
};
|
|
532
496
|
log.manualEntries.push(entry);
|
|
533
497
|
return entry;
|
|
@@ -540,12 +504,15 @@ export function editManualEntry(log, id, patch, config) {
|
|
|
540
504
|
const entry = findManualEntry(log, id);
|
|
541
505
|
if (!entry)
|
|
542
506
|
throw new Error(`Manual entry not found: ${id}`);
|
|
507
|
+
if (entry.sourceSessionId) {
|
|
508
|
+
throw new Error('Session-born entry is not editable');
|
|
509
|
+
}
|
|
543
510
|
if (patch.minutes !== undefined) {
|
|
544
511
|
if (!Number.isFinite(patch.minutes) || patch.minutes <= 0) {
|
|
545
512
|
throw new Error('Minutes must be positive');
|
|
546
513
|
}
|
|
547
|
-
if (patch.minutes >
|
|
548
|
-
throw new Error(`Max is ${
|
|
514
|
+
if (patch.minutes > MAX_ENTRY_MINUTES) {
|
|
515
|
+
throw new Error(`Max is ${MAX_ENTRY_MINUTES} minutes (8h)`);
|
|
549
516
|
}
|
|
550
517
|
const deltaMs = (patch.minutes - entry.minutes) * MS_PER_MINUTE;
|
|
551
518
|
if (deltaMs > 0 && computeTotalClaimedMs(log) + deltaMs > computeBudgetMs(log, config)) {
|
|
@@ -554,20 +521,35 @@ export function editManualEntry(log, id, patch, config) {
|
|
|
554
521
|
}
|
|
555
522
|
entry.minutes = patch.minutes;
|
|
556
523
|
}
|
|
557
|
-
|
|
558
|
-
|
|
559
|
-
|
|
560
|
-
|
|
561
|
-
|
|
562
|
-
}
|
|
563
|
-
if (patch.activity !== undefined) {
|
|
564
|
-
const a = patch.activity.trim();
|
|
565
|
-
if (!a)
|
|
524
|
+
// Validate description against the final activity — a patch may change
|
|
525
|
+
// either or both. Only Development may end up with an empty description.
|
|
526
|
+
if (patch.description !== undefined || patch.activity !== undefined) {
|
|
527
|
+
const activity = (patch.activity ?? entry.activity).trim();
|
|
528
|
+
if (!activity)
|
|
566
529
|
throw new Error('Activity cannot be empty');
|
|
567
|
-
|
|
530
|
+
const description = (patch.description ?? entry.description).trim();
|
|
531
|
+
if (!description && activity !== DEFAULT_ACTIVITY) {
|
|
532
|
+
throw new Error('Description is required (only Development may omit it)');
|
|
533
|
+
}
|
|
534
|
+
entry.activity = activity;
|
|
535
|
+
entry.description = description;
|
|
568
536
|
}
|
|
569
537
|
unsealForEdit(log);
|
|
570
538
|
}
|
|
539
|
+
/**
|
|
540
|
+
* Delete a manual entry. Session-born entries are deletable too (unlike
|
|
541
|
+
* edit) — removing one just un-claims the extra session time. Throws when
|
|
542
|
+
* the id is unknown.
|
|
543
|
+
*/
|
|
544
|
+
export function deleteManualEntry(log, id) {
|
|
545
|
+
const entries = log.manualEntries;
|
|
546
|
+
const index = entries?.findIndex(e => e.id === id) ?? -1;
|
|
547
|
+
if (!entries || index === -1)
|
|
548
|
+
throw new Error(`Manual entry not found: ${id}`);
|
|
549
|
+
const [removed] = entries.splice(index, 1);
|
|
550
|
+
unsealForEdit(log);
|
|
551
|
+
return removed;
|
|
552
|
+
}
|
|
571
553
|
/** Parse a date string + hour into a timestamp in the given timezone */
|
|
572
554
|
function parseDateWithHour(date, hour, timezone) {
|
|
573
555
|
// Build a date at noon UTC, then adjust by finding the offset
|