@redjay/threads-core 1.1.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 +21 -0
- package/README.md +42 -0
- package/dist/index.d.ts +2 -0
- package/dist/index.d.ts.map +1 -0
- package/dist/index.js +19 -0
- package/dist/index.js.map +1 -0
- package/dist/models/index.d.ts +4 -0
- package/dist/models/index.d.ts.map +1 -0
- package/dist/models/index.js +20 -0
- package/dist/models/index.js.map +1 -0
- package/dist/models/recurrence.d.ts +56 -0
- package/dist/models/recurrence.d.ts.map +1 -0
- package/dist/models/recurrence.js +350 -0
- package/dist/models/recurrence.js.map +1 -0
- package/dist/models/temperature.d.ts +92 -0
- package/dist/models/temperature.d.ts.map +1 -0
- package/dist/models/temperature.js +160 -0
- package/dist/models/temperature.js.map +1 -0
- package/dist/models/types.d.ts +102 -0
- package/dist/models/types.d.ts.map +1 -0
- package/dist/models/types.js +3 -0
- package/dist/models/types.js.map +1 -0
- package/package.json +54 -0
package/LICENSE
ADDED
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
MIT License
|
|
2
|
+
|
|
3
|
+
Copyright (c) 2026 Joshua Ramirez
|
|
4
|
+
|
|
5
|
+
Permission is hereby granted, free of charge, to any person obtaining a copy
|
|
6
|
+
of this software and associated documentation files (the "Software"), to deal
|
|
7
|
+
in the Software without restriction, including without limitation the rights
|
|
8
|
+
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
|
9
|
+
copies of the Software, and to permit persons to whom the Software is
|
|
10
|
+
furnished to do so, subject to the following conditions:
|
|
11
|
+
|
|
12
|
+
The above copyright notice and this permission notice shall be included in all
|
|
13
|
+
copies or substantial portions of the Software.
|
|
14
|
+
|
|
15
|
+
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
|
16
|
+
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
|
17
|
+
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
|
18
|
+
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
|
19
|
+
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
|
20
|
+
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
|
21
|
+
SOFTWARE.
|
package/README.md
ADDED
|
@@ -0,0 +1,42 @@
|
|
|
1
|
+
# @redjay/threads-core
|
|
2
|
+
|
|
3
|
+
Core types and models for the Threads platform.
|
|
4
|
+
|
|
5
|
+
## Installation
|
|
6
|
+
|
|
7
|
+
```bash
|
|
8
|
+
npm install @redjay/threads-core
|
|
9
|
+
```
|
|
10
|
+
|
|
11
|
+
## Usage
|
|
12
|
+
|
|
13
|
+
```typescript
|
|
14
|
+
import { Thread, Container, Progress, ThreadStatus, Temperature } from '@redjay/threads-core';
|
|
15
|
+
import { createThread, createProgress } from '@redjay/threads-core/models';
|
|
16
|
+
```
|
|
17
|
+
|
|
18
|
+
## Types
|
|
19
|
+
|
|
20
|
+
### Thread
|
|
21
|
+
|
|
22
|
+
Represents a stream of activity with:
|
|
23
|
+
- `status`: active, paused, stopped, completed, archived
|
|
24
|
+
- `temperature`: frozen, freezing, cold, tepid, warm, hot (momentum indicator)
|
|
25
|
+
- `size`: tiny, small, medium, large, huge (scope)
|
|
26
|
+
- `importance`: 1-5 priority level
|
|
27
|
+
|
|
28
|
+
### Container
|
|
29
|
+
|
|
30
|
+
Organizational node for grouping threads without momentum semantics.
|
|
31
|
+
|
|
32
|
+
### Progress
|
|
33
|
+
|
|
34
|
+
Timestamped notes for tracking activity on a thread.
|
|
35
|
+
|
|
36
|
+
### Dependencies
|
|
37
|
+
|
|
38
|
+
Links between threads with why/what/how/when context.
|
|
39
|
+
|
|
40
|
+
## License
|
|
41
|
+
|
|
42
|
+
MIT
|
package/dist/index.d.ts
ADDED
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AACA,cAAc,UAAU,CAAC"}
|
package/dist/index.js
ADDED
|
@@ -0,0 +1,19 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
var __createBinding = (this && this.__createBinding) || (Object.create ? (function(o, m, k, k2) {
|
|
3
|
+
if (k2 === undefined) k2 = k;
|
|
4
|
+
var desc = Object.getOwnPropertyDescriptor(m, k);
|
|
5
|
+
if (!desc || ("get" in desc ? !m.__esModule : desc.writable || desc.configurable)) {
|
|
6
|
+
desc = { enumerable: true, get: function() { return m[k]; } };
|
|
7
|
+
}
|
|
8
|
+
Object.defineProperty(o, k2, desc);
|
|
9
|
+
}) : (function(o, m, k, k2) {
|
|
10
|
+
if (k2 === undefined) k2 = k;
|
|
11
|
+
o[k2] = m[k];
|
|
12
|
+
}));
|
|
13
|
+
var __exportStar = (this && this.__exportStar) || function(m, exports) {
|
|
14
|
+
for (var p in m) if (p !== "default" && !Object.prototype.hasOwnProperty.call(exports, p)) __createBinding(exports, m, p);
|
|
15
|
+
};
|
|
16
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
17
|
+
// Re-export all models
|
|
18
|
+
__exportStar(require("./models"), exports);
|
|
19
|
+
//# sourceMappingURL=index.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"index.js","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":";;;;;;;;;;;;;;;;AAAA,uBAAuB;AACvB,2CAAyB"}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../src/models/index.ts"],"names":[],"mappings":"AAAA,cAAc,SAAS,CAAC;AACxB,cAAc,eAAe,CAAC;AAC9B,cAAc,cAAc,CAAC"}
|
|
@@ -0,0 +1,20 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
var __createBinding = (this && this.__createBinding) || (Object.create ? (function(o, m, k, k2) {
|
|
3
|
+
if (k2 === undefined) k2 = k;
|
|
4
|
+
var desc = Object.getOwnPropertyDescriptor(m, k);
|
|
5
|
+
if (!desc || ("get" in desc ? !m.__esModule : desc.writable || desc.configurable)) {
|
|
6
|
+
desc = { enumerable: true, get: function() { return m[k]; } };
|
|
7
|
+
}
|
|
8
|
+
Object.defineProperty(o, k2, desc);
|
|
9
|
+
}) : (function(o, m, k, k2) {
|
|
10
|
+
if (k2 === undefined) k2 = k;
|
|
11
|
+
o[k2] = m[k];
|
|
12
|
+
}));
|
|
13
|
+
var __exportStar = (this && this.__exportStar) || function(m, exports) {
|
|
14
|
+
for (var p in m) if (p !== "default" && !Object.prototype.hasOwnProperty.call(exports, p)) __createBinding(exports, m, p);
|
|
15
|
+
};
|
|
16
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
17
|
+
__exportStar(require("./types"), exports);
|
|
18
|
+
__exportStar(require("./temperature"), exports);
|
|
19
|
+
__exportStar(require("./recurrence"), exports);
|
|
20
|
+
//# sourceMappingURL=index.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"index.js","sourceRoot":"","sources":["../../src/models/index.ts"],"names":[],"mappings":";;;;;;;;;;;;;;;;AAAA,0CAAwB;AACxB,gDAA8B;AAC9B,+CAA6B"}
|
|
@@ -0,0 +1,56 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Recurrence calculation utilities for reminder scheduling.
|
|
3
|
+
*
|
|
4
|
+
* Handles composite recurrence patterns: interval + unit + weekday patterns.
|
|
5
|
+
*/
|
|
6
|
+
import { RecurrencePattern, Reminder, Weekday } from './types';
|
|
7
|
+
/**
|
|
8
|
+
* Calculate the next occurrence of a recurrence pattern after a given date.
|
|
9
|
+
*
|
|
10
|
+
* @param pattern - The recurrence pattern
|
|
11
|
+
* @param after - Calculate next occurrence after this date
|
|
12
|
+
* @returns The next occurrence date
|
|
13
|
+
*/
|
|
14
|
+
export declare function getNextOccurrence(pattern: RecurrencePattern, after: Date): Date;
|
|
15
|
+
/**
|
|
16
|
+
* Check if a reminder is overdue.
|
|
17
|
+
*
|
|
18
|
+
* @param reminder - The reminder to check
|
|
19
|
+
* @param now - Reference time (defaults to current time)
|
|
20
|
+
* @returns True if the reminder is overdue
|
|
21
|
+
*/
|
|
22
|
+
export declare function isOverdue(reminder: Reminder, now?: Date): boolean;
|
|
23
|
+
/**
|
|
24
|
+
* Check if a reminder is due today.
|
|
25
|
+
*
|
|
26
|
+
* @param reminder - The reminder to check
|
|
27
|
+
* @param now - Reference time (defaults to current time)
|
|
28
|
+
* @returns True if the reminder is due today
|
|
29
|
+
*/
|
|
30
|
+
export declare function isDueToday(reminder: Reminder, now?: Date): boolean;
|
|
31
|
+
/**
|
|
32
|
+
* Check if a reminder is currently active (due or overdue, not dismissed).
|
|
33
|
+
*
|
|
34
|
+
* @param reminder - The reminder to check
|
|
35
|
+
* @param now - Reference time (defaults to current time)
|
|
36
|
+
* @returns True if the reminder should be shown
|
|
37
|
+
*/
|
|
38
|
+
export declare function isActive(reminder: Reminder, now?: Date): boolean;
|
|
39
|
+
/**
|
|
40
|
+
* Advance a recurring reminder to its next occurrence.
|
|
41
|
+
* Returns a new reminder object with updated dueAt.
|
|
42
|
+
*
|
|
43
|
+
* @param reminder - The reminder to advance
|
|
44
|
+
* @param now - Reference time for calculating next occurrence
|
|
45
|
+
* @returns Updated reminder with new dueAt
|
|
46
|
+
*/
|
|
47
|
+
export declare function advanceReminder(reminder: Reminder, now?: Date): Reminder;
|
|
48
|
+
/**
|
|
49
|
+
* Format a recurrence pattern for display.
|
|
50
|
+
*/
|
|
51
|
+
export declare function formatRecurrence(pattern: RecurrencePattern): string;
|
|
52
|
+
/**
|
|
53
|
+
* Parse weekday string to Weekday type.
|
|
54
|
+
*/
|
|
55
|
+
export declare function parseWeekday(str: string): Weekday | null;
|
|
56
|
+
//# sourceMappingURL=recurrence.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"recurrence.d.ts","sourceRoot":"","sources":["../../src/models/recurrence.ts"],"names":[],"mappings":"AAAA;;;;GAIG;AAEH,OAAO,EAAE,iBAAiB,EAAE,QAAQ,EAAE,OAAO,EAAE,MAAM,SAAS,CAAC;AAuF/D;;;;;;GAMG;AACH,wBAAgB,iBAAiB,CAAC,OAAO,EAAE,iBAAiB,EAAE,KAAK,EAAE,IAAI,GAAG,IAAI,CAiB/E;AAuID;;;;;;GAMG;AACH,wBAAgB,SAAS,CAAC,QAAQ,EAAE,QAAQ,EAAE,GAAG,GAAE,IAAiB,GAAG,OAAO,CAQ7E;AAED;;;;;;GAMG;AACH,wBAAgB,UAAU,CAAC,QAAQ,EAAE,QAAQ,EAAE,GAAG,GAAE,IAAiB,GAAG,OAAO,CAU9E;AAED;;;;;;GAMG;AACH,wBAAgB,QAAQ,CAAC,QAAQ,EAAE,QAAQ,EAAE,GAAG,GAAE,IAAiB,GAAG,OAAO,CAO5E;AAED;;;;;;;GAOG;AACH,wBAAgB,eAAe,CAAC,QAAQ,EAAE,QAAQ,EAAE,GAAG,GAAE,IAAiB,GAAG,QAAQ,CAapF;AAED;;GAEG;AACH,wBAAgB,gBAAgB,CAAC,OAAO,EAAE,iBAAiB,GAAG,MAAM,CAqCnE;AAeD;;GAEG;AACH,wBAAgB,YAAY,CAAC,GAAG,EAAE,MAAM,GAAG,OAAO,GAAG,IAAI,CAqBxD"}
|
|
@@ -0,0 +1,350 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
/**
|
|
3
|
+
* Recurrence calculation utilities for reminder scheduling.
|
|
4
|
+
*
|
|
5
|
+
* Handles composite recurrence patterns: interval + unit + weekday patterns.
|
|
6
|
+
*/
|
|
7
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
8
|
+
exports.getNextOccurrence = getNextOccurrence;
|
|
9
|
+
exports.isOverdue = isOverdue;
|
|
10
|
+
exports.isDueToday = isDueToday;
|
|
11
|
+
exports.isActive = isActive;
|
|
12
|
+
exports.advanceReminder = advanceReminder;
|
|
13
|
+
exports.formatRecurrence = formatRecurrence;
|
|
14
|
+
exports.parseWeekday = parseWeekday;
|
|
15
|
+
// Weekday to JS Date.getDay() mapping (0=Sunday, 1=Monday, etc.)
|
|
16
|
+
const WEEKDAY_MAP = {
|
|
17
|
+
sunday: 0,
|
|
18
|
+
monday: 1,
|
|
19
|
+
tuesday: 2,
|
|
20
|
+
wednesday: 3,
|
|
21
|
+
thursday: 4,
|
|
22
|
+
friday: 5,
|
|
23
|
+
saturday: 6,
|
|
24
|
+
};
|
|
25
|
+
// Reverse mapping for nth weekday calculations
|
|
26
|
+
const DAY_TO_WEEKDAY = [
|
|
27
|
+
'sunday', 'monday', 'tuesday', 'wednesday', 'thursday', 'friday', 'saturday'
|
|
28
|
+
];
|
|
29
|
+
/**
|
|
30
|
+
* Get the start of day (midnight) for a date.
|
|
31
|
+
*/
|
|
32
|
+
function startOfDay(date) {
|
|
33
|
+
const d = new Date(date);
|
|
34
|
+
d.setHours(0, 0, 0, 0);
|
|
35
|
+
return d;
|
|
36
|
+
}
|
|
37
|
+
/**
|
|
38
|
+
* Add days to a date.
|
|
39
|
+
*/
|
|
40
|
+
function addDays(date, days) {
|
|
41
|
+
const result = new Date(date);
|
|
42
|
+
result.setDate(result.getDate() + days);
|
|
43
|
+
return result;
|
|
44
|
+
}
|
|
45
|
+
/**
|
|
46
|
+
* Add months to a date.
|
|
47
|
+
*/
|
|
48
|
+
function addMonths(date, months) {
|
|
49
|
+
const result = new Date(date);
|
|
50
|
+
result.setMonth(result.getMonth() + months);
|
|
51
|
+
return result;
|
|
52
|
+
}
|
|
53
|
+
/**
|
|
54
|
+
* Get the nth occurrence of a weekday in a given month.
|
|
55
|
+
* nth=5 means "last" occurrence.
|
|
56
|
+
*/
|
|
57
|
+
function getNthWeekdayOfMonth(year, month, weekday, nth) {
|
|
58
|
+
const targetDay = WEEKDAY_MAP[weekday];
|
|
59
|
+
if (nth === 5) {
|
|
60
|
+
// "Last" weekday of month: start from last day and work backwards
|
|
61
|
+
const lastDay = new Date(year, month + 1, 0); // Last day of month
|
|
62
|
+
let current = new Date(lastDay);
|
|
63
|
+
while (current.getMonth() === month) {
|
|
64
|
+
if (current.getDay() === targetDay) {
|
|
65
|
+
return current;
|
|
66
|
+
}
|
|
67
|
+
current = addDays(current, -1);
|
|
68
|
+
}
|
|
69
|
+
return null;
|
|
70
|
+
}
|
|
71
|
+
// Find nth occurrence (1-4)
|
|
72
|
+
const firstOfMonth = new Date(year, month, 1);
|
|
73
|
+
const firstWeekday = firstOfMonth.getDay();
|
|
74
|
+
// Calculate day of first occurrence of target weekday
|
|
75
|
+
let daysToAdd = targetDay - firstWeekday;
|
|
76
|
+
if (daysToAdd < 0)
|
|
77
|
+
daysToAdd += 7;
|
|
78
|
+
const firstOccurrence = addDays(firstOfMonth, daysToAdd);
|
|
79
|
+
// Add weeks to get nth occurrence
|
|
80
|
+
const nthOccurrence = addDays(firstOccurrence, (nth - 1) * 7);
|
|
81
|
+
// Verify still in same month
|
|
82
|
+
if (nthOccurrence.getMonth() !== month) {
|
|
83
|
+
return null;
|
|
84
|
+
}
|
|
85
|
+
return nthOccurrence;
|
|
86
|
+
}
|
|
87
|
+
/**
|
|
88
|
+
* Calculate the next occurrence of a recurrence pattern after a given date.
|
|
89
|
+
*
|
|
90
|
+
* @param pattern - The recurrence pattern
|
|
91
|
+
* @param after - Calculate next occurrence after this date
|
|
92
|
+
* @returns The next occurrence date
|
|
93
|
+
*/
|
|
94
|
+
function getNextOccurrence(pattern, after) {
|
|
95
|
+
const afterDate = startOfDay(after);
|
|
96
|
+
switch (pattern.unit) {
|
|
97
|
+
case 'day':
|
|
98
|
+
return getNextDayOccurrence(pattern, afterDate);
|
|
99
|
+
case 'week':
|
|
100
|
+
return getNextWeekOccurrence(pattern, afterDate);
|
|
101
|
+
case 'month':
|
|
102
|
+
return getNextMonthOccurrence(pattern, afterDate);
|
|
103
|
+
default:
|
|
104
|
+
// Fallback: add interval days
|
|
105
|
+
return addDays(afterDate, pattern.interval);
|
|
106
|
+
}
|
|
107
|
+
}
|
|
108
|
+
/**
|
|
109
|
+
* Calculate next occurrence for day-based patterns.
|
|
110
|
+
*/
|
|
111
|
+
function getNextDayOccurrence(pattern, after) {
|
|
112
|
+
return addDays(after, pattern.interval);
|
|
113
|
+
}
|
|
114
|
+
/**
|
|
115
|
+
* Calculate next occurrence for week-based patterns.
|
|
116
|
+
*/
|
|
117
|
+
function getNextWeekOccurrence(pattern, after) {
|
|
118
|
+
const weekdays = pattern.weekdays ?? [];
|
|
119
|
+
if (weekdays.length === 0) {
|
|
120
|
+
// Simple weekly interval with no specific weekdays
|
|
121
|
+
return addDays(after, pattern.interval * 7);
|
|
122
|
+
}
|
|
123
|
+
// Convert weekdays to day numbers and sort
|
|
124
|
+
const targetDays = weekdays.map(w => WEEKDAY_MAP[w]).sort((a, b) => a - b);
|
|
125
|
+
const currentDay = after.getDay();
|
|
126
|
+
// Find next weekday in current week
|
|
127
|
+
for (const targetDay of targetDays) {
|
|
128
|
+
if (targetDay > currentDay) {
|
|
129
|
+
return addDays(after, targetDay - currentDay);
|
|
130
|
+
}
|
|
131
|
+
}
|
|
132
|
+
// Next occurrence is in a future week
|
|
133
|
+
// For interval=1, it's the first weekday of next week
|
|
134
|
+
// For interval>1, we need to skip (interval-1) weeks
|
|
135
|
+
const daysToNextWeek = 7 - currentDay + targetDays[0];
|
|
136
|
+
const additionalWeeks = (pattern.interval - 1) * 7;
|
|
137
|
+
return addDays(after, daysToNextWeek + additionalWeeks);
|
|
138
|
+
}
|
|
139
|
+
/**
|
|
140
|
+
* Calculate next occurrence for month-based patterns.
|
|
141
|
+
*/
|
|
142
|
+
function getNextMonthOccurrence(pattern, after) {
|
|
143
|
+
if (pattern.nthWeekday) {
|
|
144
|
+
return getNextNthWeekdayOccurrence(pattern, after);
|
|
145
|
+
}
|
|
146
|
+
if (pattern.dayOfMonth) {
|
|
147
|
+
return getNextDayOfMonthOccurrence(pattern, after);
|
|
148
|
+
}
|
|
149
|
+
// Default: same day of month, N months later
|
|
150
|
+
// Must preserve target day before month arithmetic to avoid rollover issues
|
|
151
|
+
const targetDay = after.getDate();
|
|
152
|
+
let year = after.getFullYear();
|
|
153
|
+
let month = after.getMonth() + pattern.interval;
|
|
154
|
+
// Handle year rollover
|
|
155
|
+
if (month > 11) {
|
|
156
|
+
year += Math.floor(month / 12);
|
|
157
|
+
month = month % 12;
|
|
158
|
+
}
|
|
159
|
+
// Handle month-end edge cases (e.g., Jan 31 -> Feb 28)
|
|
160
|
+
const maxDay = new Date(year, month + 1, 0).getDate();
|
|
161
|
+
const actualDay = Math.min(targetDay, maxDay);
|
|
162
|
+
return new Date(year, month, actualDay);
|
|
163
|
+
}
|
|
164
|
+
/**
|
|
165
|
+
* Calculate next occurrence for nth weekday of month patterns.
|
|
166
|
+
*/
|
|
167
|
+
function getNextNthWeekdayOccurrence(pattern, after) {
|
|
168
|
+
const { nth, weekday } = pattern.nthWeekday;
|
|
169
|
+
let year = after.getFullYear();
|
|
170
|
+
let month = after.getMonth();
|
|
171
|
+
// Try current month first
|
|
172
|
+
let occurrence = getNthWeekdayOfMonth(year, month, weekday, nth);
|
|
173
|
+
if (occurrence && occurrence > after) {
|
|
174
|
+
return occurrence;
|
|
175
|
+
}
|
|
176
|
+
// Try future months with interval
|
|
177
|
+
for (let i = 0; i < 24; i++) { // Safety limit
|
|
178
|
+
month += pattern.interval;
|
|
179
|
+
if (month > 11) {
|
|
180
|
+
year += Math.floor(month / 12);
|
|
181
|
+
month = month % 12;
|
|
182
|
+
}
|
|
183
|
+
occurrence = getNthWeekdayOfMonth(year, month, weekday, nth);
|
|
184
|
+
if (occurrence && occurrence > after) {
|
|
185
|
+
return occurrence;
|
|
186
|
+
}
|
|
187
|
+
}
|
|
188
|
+
// Fallback
|
|
189
|
+
return addMonths(after, pattern.interval);
|
|
190
|
+
}
|
|
191
|
+
/**
|
|
192
|
+
* Calculate next occurrence for specific day of month patterns.
|
|
193
|
+
*/
|
|
194
|
+
function getNextDayOfMonthOccurrence(pattern, after) {
|
|
195
|
+
const targetDay = pattern.dayOfMonth;
|
|
196
|
+
let year = after.getFullYear();
|
|
197
|
+
let month = after.getMonth();
|
|
198
|
+
// Check if target day in current month is still in the future
|
|
199
|
+
const maxDayCurrentMonth = new Date(year, month + 1, 0).getDate();
|
|
200
|
+
const actualDayCurrentMonth = Math.min(targetDay, maxDayCurrentMonth);
|
|
201
|
+
const currentMonthCandidate = new Date(year, month, actualDayCurrentMonth);
|
|
202
|
+
if (currentMonthCandidate > after) {
|
|
203
|
+
return currentMonthCandidate;
|
|
204
|
+
}
|
|
205
|
+
// Move to future month with interval
|
|
206
|
+
month += pattern.interval;
|
|
207
|
+
if (month > 11) {
|
|
208
|
+
year += Math.floor(month / 12);
|
|
209
|
+
month = month % 12;
|
|
210
|
+
}
|
|
211
|
+
const maxDayTargetMonth = new Date(year, month + 1, 0).getDate();
|
|
212
|
+
const actualDay = Math.min(targetDay, maxDayTargetMonth);
|
|
213
|
+
return new Date(year, month, actualDay);
|
|
214
|
+
}
|
|
215
|
+
/**
|
|
216
|
+
* Check if a reminder is overdue.
|
|
217
|
+
*
|
|
218
|
+
* @param reminder - The reminder to check
|
|
219
|
+
* @param now - Reference time (defaults to current time)
|
|
220
|
+
* @returns True if the reminder is overdue
|
|
221
|
+
*/
|
|
222
|
+
function isOverdue(reminder, now = new Date()) {
|
|
223
|
+
// Dismissed one-time reminders are never overdue
|
|
224
|
+
if (reminder.dismissedAt && !reminder.recurrence) {
|
|
225
|
+
return false;
|
|
226
|
+
}
|
|
227
|
+
const dueDate = new Date(reminder.dueAt);
|
|
228
|
+
return dueDate < startOfDay(now);
|
|
229
|
+
}
|
|
230
|
+
/**
|
|
231
|
+
* Check if a reminder is due today.
|
|
232
|
+
*
|
|
233
|
+
* @param reminder - The reminder to check
|
|
234
|
+
* @param now - Reference time (defaults to current time)
|
|
235
|
+
* @returns True if the reminder is due today
|
|
236
|
+
*/
|
|
237
|
+
function isDueToday(reminder, now = new Date()) {
|
|
238
|
+
// Dismissed one-time reminders are never due
|
|
239
|
+
if (reminder.dismissedAt && !reminder.recurrence) {
|
|
240
|
+
return false;
|
|
241
|
+
}
|
|
242
|
+
const dueDate = startOfDay(new Date(reminder.dueAt));
|
|
243
|
+
const today = startOfDay(now);
|
|
244
|
+
return dueDate.getTime() === today.getTime();
|
|
245
|
+
}
|
|
246
|
+
/**
|
|
247
|
+
* Check if a reminder is currently active (due or overdue, not dismissed).
|
|
248
|
+
*
|
|
249
|
+
* @param reminder - The reminder to check
|
|
250
|
+
* @param now - Reference time (defaults to current time)
|
|
251
|
+
* @returns True if the reminder should be shown
|
|
252
|
+
*/
|
|
253
|
+
function isActive(reminder, now = new Date()) {
|
|
254
|
+
// Dismissed one-time reminders are not active
|
|
255
|
+
if (reminder.dismissedAt && !reminder.recurrence) {
|
|
256
|
+
return false;
|
|
257
|
+
}
|
|
258
|
+
return isOverdue(reminder, now) || isDueToday(reminder, now);
|
|
259
|
+
}
|
|
260
|
+
/**
|
|
261
|
+
* Advance a recurring reminder to its next occurrence.
|
|
262
|
+
* Returns a new reminder object with updated dueAt.
|
|
263
|
+
*
|
|
264
|
+
* @param reminder - The reminder to advance
|
|
265
|
+
* @param now - Reference time for calculating next occurrence
|
|
266
|
+
* @returns Updated reminder with new dueAt
|
|
267
|
+
*/
|
|
268
|
+
function advanceReminder(reminder, now = new Date()) {
|
|
269
|
+
if (!reminder.recurrence) {
|
|
270
|
+
// One-time reminders cannot be advanced
|
|
271
|
+
return reminder;
|
|
272
|
+
}
|
|
273
|
+
const nextDue = getNextOccurrence(reminder.recurrence, now);
|
|
274
|
+
return {
|
|
275
|
+
...reminder,
|
|
276
|
+
dueAt: nextDue.toISOString(),
|
|
277
|
+
lastTriggeredAt: now.toISOString(),
|
|
278
|
+
};
|
|
279
|
+
}
|
|
280
|
+
/**
|
|
281
|
+
* Format a recurrence pattern for display.
|
|
282
|
+
*/
|
|
283
|
+
function formatRecurrence(pattern) {
|
|
284
|
+
const { interval, unit, weekdays, dayOfMonth, nthWeekday } = pattern;
|
|
285
|
+
if (unit === 'day') {
|
|
286
|
+
return interval === 1 ? 'daily' : `every ${interval} days`;
|
|
287
|
+
}
|
|
288
|
+
if (unit === 'week') {
|
|
289
|
+
const weekdayStr = weekdays?.join(', ') || '';
|
|
290
|
+
if (interval === 1) {
|
|
291
|
+
return weekdayStr ? `weekly on ${weekdayStr}` : 'weekly';
|
|
292
|
+
}
|
|
293
|
+
return weekdayStr
|
|
294
|
+
? `every ${interval} weeks on ${weekdayStr}`
|
|
295
|
+
: `every ${interval} weeks`;
|
|
296
|
+
}
|
|
297
|
+
if (unit === 'month') {
|
|
298
|
+
if (nthWeekday) {
|
|
299
|
+
const nthStr = nthWeekday.nth === 5 ? 'last' : `${nthWeekday.nth}${getOrdinalSuffix(nthWeekday.nth)}`;
|
|
300
|
+
if (interval === 1) {
|
|
301
|
+
return `monthly on ${nthStr} ${nthWeekday.weekday}`;
|
|
302
|
+
}
|
|
303
|
+
return `every ${interval} months on ${nthStr} ${nthWeekday.weekday}`;
|
|
304
|
+
}
|
|
305
|
+
if (dayOfMonth) {
|
|
306
|
+
if (interval === 1) {
|
|
307
|
+
return `monthly on day ${dayOfMonth}`;
|
|
308
|
+
}
|
|
309
|
+
return `every ${interval} months on day ${dayOfMonth}`;
|
|
310
|
+
}
|
|
311
|
+
return interval === 1 ? 'monthly' : `every ${interval} months`;
|
|
312
|
+
}
|
|
313
|
+
return `every ${interval} ${unit}(s)`;
|
|
314
|
+
}
|
|
315
|
+
/**
|
|
316
|
+
* Get ordinal suffix for a number (1st, 2nd, 3rd, 4th).
|
|
317
|
+
*/
|
|
318
|
+
function getOrdinalSuffix(n) {
|
|
319
|
+
if (n >= 11 && n <= 13)
|
|
320
|
+
return 'th';
|
|
321
|
+
switch (n % 10) {
|
|
322
|
+
case 1: return 'st';
|
|
323
|
+
case 2: return 'nd';
|
|
324
|
+
case 3: return 'rd';
|
|
325
|
+
default: return 'th';
|
|
326
|
+
}
|
|
327
|
+
}
|
|
328
|
+
/**
|
|
329
|
+
* Parse weekday string to Weekday type.
|
|
330
|
+
*/
|
|
331
|
+
function parseWeekday(str) {
|
|
332
|
+
const lower = str.toLowerCase().trim();
|
|
333
|
+
const weekdays = ['monday', 'tuesday', 'wednesday', 'thursday', 'friday', 'saturday', 'sunday'];
|
|
334
|
+
// Exact match
|
|
335
|
+
if (weekdays.includes(lower)) {
|
|
336
|
+
return lower;
|
|
337
|
+
}
|
|
338
|
+
// Abbreviation match (mon, tue, wed, etc.)
|
|
339
|
+
const abbrevMap = {
|
|
340
|
+
'mon': 'monday',
|
|
341
|
+
'tue': 'tuesday',
|
|
342
|
+
'wed': 'wednesday',
|
|
343
|
+
'thu': 'thursday',
|
|
344
|
+
'fri': 'friday',
|
|
345
|
+
'sat': 'saturday',
|
|
346
|
+
'sun': 'sunday',
|
|
347
|
+
};
|
|
348
|
+
return abbrevMap[lower.slice(0, 3)] ?? null;
|
|
349
|
+
}
|
|
350
|
+
//# sourceMappingURL=recurrence.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"recurrence.js","sourceRoot":"","sources":["../../src/models/recurrence.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,92 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Temperature computation module.
|
|
3
|
+
*
|
|
4
|
+
* Temperature is derived from updatedAt timestamp, not stored.
|
|
5
|
+
* This provides automatic momentum indication based on recency.
|
|
6
|
+
*
|
|
7
|
+
* Thresholds are in BUSINESS DAYS (Mon-Fri, excludes weekends).
|
|
8
|
+
*
|
|
9
|
+
* Configurable via:
|
|
10
|
+
* 1. Environment variables: THREADS_TEMP_HOT, THREADS_TEMP_WARM, etc.
|
|
11
|
+
* 2. Config file: ~/.threads/config.json { temperatureThresholds: { hot: 3, ... } }
|
|
12
|
+
* Config file takes precedence over environment variables.
|
|
13
|
+
*/
|
|
14
|
+
import { Temperature } from './types';
|
|
15
|
+
/**
|
|
16
|
+
* Configuration for temperature thresholds (in business days).
|
|
17
|
+
*/
|
|
18
|
+
export interface TemperatureThresholdConfig {
|
|
19
|
+
hot: number;
|
|
20
|
+
warm: number;
|
|
21
|
+
tepid: number;
|
|
22
|
+
cold: number;
|
|
23
|
+
freezing: number;
|
|
24
|
+
}
|
|
25
|
+
/**
|
|
26
|
+
* Default thresholds for computing temperature from recency (in business days).
|
|
27
|
+
*/
|
|
28
|
+
export declare const DEFAULT_TEMPERATURE_THRESHOLDS: TemperatureThresholdConfig;
|
|
29
|
+
/**
|
|
30
|
+
* Environment variable names for threshold configuration.
|
|
31
|
+
*/
|
|
32
|
+
export declare const TEMPERATURE_ENV_VARS: {
|
|
33
|
+
readonly hot: "THREADS_TEMP_HOT";
|
|
34
|
+
readonly warm: "THREADS_TEMP_WARM";
|
|
35
|
+
readonly tepid: "THREADS_TEMP_TEPID";
|
|
36
|
+
readonly cold: "THREADS_TEMP_COLD";
|
|
37
|
+
readonly freezing: "THREADS_TEMP_FREEZING";
|
|
38
|
+
};
|
|
39
|
+
/**
|
|
40
|
+
* Get thresholds from environment variables.
|
|
41
|
+
* Returns only the values that are set.
|
|
42
|
+
*/
|
|
43
|
+
export declare function getThresholdsFromEnv(): Partial<TemperatureThresholdConfig>;
|
|
44
|
+
/**
|
|
45
|
+
* Configure temperature thresholds.
|
|
46
|
+
* Call this at application startup after loading config.
|
|
47
|
+
*
|
|
48
|
+
* Priority: defaults < env vars < config file
|
|
49
|
+
*
|
|
50
|
+
* @param fileConfig - Thresholds from config file (highest priority)
|
|
51
|
+
*/
|
|
52
|
+
export declare function configureTemperatureThresholds(fileConfig?: Partial<TemperatureThresholdConfig>): void;
|
|
53
|
+
/**
|
|
54
|
+
* Get the current temperature threshold configuration.
|
|
55
|
+
*/
|
|
56
|
+
export declare function getTemperatureThresholds(): TemperatureThresholdConfig;
|
|
57
|
+
/**
|
|
58
|
+
* Reset thresholds to defaults (useful for testing).
|
|
59
|
+
*/
|
|
60
|
+
export declare function resetTemperatureThresholds(): void;
|
|
61
|
+
/**
|
|
62
|
+
* Current thresholds array (for backward compatibility).
|
|
63
|
+
* Note: This is now computed dynamically from currentConfig.
|
|
64
|
+
*/
|
|
65
|
+
export declare const TEMPERATURE_THRESHOLDS: {
|
|
66
|
+
maxDays: number;
|
|
67
|
+
temperature: Temperature;
|
|
68
|
+
}[];
|
|
69
|
+
/**
|
|
70
|
+
* Temperature ordering from hottest to coldest.
|
|
71
|
+
* Useful for sorting and comparison.
|
|
72
|
+
*/
|
|
73
|
+
export declare const TEMPERATURE_ORDER: Temperature[];
|
|
74
|
+
/**
|
|
75
|
+
* Count business days (Mon-Fri) between two dates.
|
|
76
|
+
* Excludes weekends (Saturday = 6, Sunday = 0).
|
|
77
|
+
*
|
|
78
|
+
* @param from - Start date (earlier)
|
|
79
|
+
* @param to - End date (later, typically now)
|
|
80
|
+
* @returns Number of business days elapsed
|
|
81
|
+
*/
|
|
82
|
+
export declare function countBusinessDays(from: Date, to: Date): number;
|
|
83
|
+
/**
|
|
84
|
+
* Compute temperature from updatedAt timestamp.
|
|
85
|
+
* Uses business days (Mon-Fri) for calculation.
|
|
86
|
+
*
|
|
87
|
+
* @param updatedAt - ISO timestamp of last update
|
|
88
|
+
* @param now - Current time (injectable for testing)
|
|
89
|
+
* @returns Computed temperature based on recency in business days
|
|
90
|
+
*/
|
|
91
|
+
export declare function computeTemperature(updatedAt: string, now?: Date): Temperature;
|
|
92
|
+
//# sourceMappingURL=temperature.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"temperature.d.ts","sourceRoot":"","sources":["../../src/models/temperature.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;GAYG;AAEH,OAAO,EAAE,WAAW,EAAE,MAAM,SAAS,CAAC;AAEtC;;GAEG;AACH,MAAM,WAAW,0BAA0B;IACzC,GAAG,EAAE,MAAM,CAAC;IACZ,IAAI,EAAE,MAAM,CAAC;IACb,KAAK,EAAE,MAAM,CAAC;IACd,IAAI,EAAE,MAAM,CAAC;IACb,QAAQ,EAAE,MAAM,CAAC;CAElB;AAED;;GAEG;AACH,eAAO,MAAM,8BAA8B,EAAE,0BAM5C,CAAC;AAEF;;GAEG;AACH,eAAO,MAAM,oBAAoB;;;;;;CAMvB,CAAC;AAmBX;;;GAGG;AACH,wBAAgB,oBAAoB,IAAI,OAAO,CAAC,0BAA0B,CAAC,CAc1E;AAED;;;;;;;GAOG;AACH,wBAAgB,8BAA8B,CAC5C,UAAU,CAAC,EAAE,OAAO,CAAC,0BAA0B,CAAC,GAC/C,IAAI,CAQN;AAED;;GAEG;AACH,wBAAgB,wBAAwB,IAAI,0BAA0B,CAErE;AAED;;GAEG;AACH,wBAAgB,0BAA0B,IAAI,IAAI,CAEjD;AAED;;;GAGG;AACH,eAAO,MAAM,sBAAsB;;iBAnEc,WAAW;GAmEyB,CAAC;AAEtF;;;GAGG;AACH,eAAO,MAAM,iBAAiB,EAAE,WAAW,EAA2D,CAAC;AAEvG;;;;;;;GAOG;AACH,wBAAgB,iBAAiB,CAAC,IAAI,EAAE,IAAI,EAAE,EAAE,EAAE,IAAI,GAAG,MAAM,CAuB9D;AAED;;;;;;;GAOG;AACH,wBAAgB,kBAAkB,CAAC,SAAS,EAAE,MAAM,EAAE,GAAG,GAAE,IAAiB,GAAG,WAAW,CAazF"}
|
|
@@ -0,0 +1,160 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
/**
|
|
3
|
+
* Temperature computation module.
|
|
4
|
+
*
|
|
5
|
+
* Temperature is derived from updatedAt timestamp, not stored.
|
|
6
|
+
* This provides automatic momentum indication based on recency.
|
|
7
|
+
*
|
|
8
|
+
* Thresholds are in BUSINESS DAYS (Mon-Fri, excludes weekends).
|
|
9
|
+
*
|
|
10
|
+
* Configurable via:
|
|
11
|
+
* 1. Environment variables: THREADS_TEMP_HOT, THREADS_TEMP_WARM, etc.
|
|
12
|
+
* 2. Config file: ~/.threads/config.json { temperatureThresholds: { hot: 3, ... } }
|
|
13
|
+
* Config file takes precedence over environment variables.
|
|
14
|
+
*/
|
|
15
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
16
|
+
exports.TEMPERATURE_ORDER = exports.TEMPERATURE_THRESHOLDS = exports.TEMPERATURE_ENV_VARS = exports.DEFAULT_TEMPERATURE_THRESHOLDS = void 0;
|
|
17
|
+
exports.getThresholdsFromEnv = getThresholdsFromEnv;
|
|
18
|
+
exports.configureTemperatureThresholds = configureTemperatureThresholds;
|
|
19
|
+
exports.getTemperatureThresholds = getTemperatureThresholds;
|
|
20
|
+
exports.resetTemperatureThresholds = resetTemperatureThresholds;
|
|
21
|
+
exports.countBusinessDays = countBusinessDays;
|
|
22
|
+
exports.computeTemperature = computeTemperature;
|
|
23
|
+
/**
|
|
24
|
+
* Default thresholds for computing temperature from recency (in business days).
|
|
25
|
+
*/
|
|
26
|
+
exports.DEFAULT_TEMPERATURE_THRESHOLDS = {
|
|
27
|
+
hot: 5, // 1 week (5 business days)
|
|
28
|
+
warm: 10, // 2 weeks (10 business days)
|
|
29
|
+
tepid: 15, // 3 weeks (15 business days)
|
|
30
|
+
cold: 20, // 4 weeks / ~1 month (20 business days)
|
|
31
|
+
freezing: 40, // ~2 months (40 business days)
|
|
32
|
+
};
|
|
33
|
+
/**
|
|
34
|
+
* Environment variable names for threshold configuration.
|
|
35
|
+
*/
|
|
36
|
+
exports.TEMPERATURE_ENV_VARS = {
|
|
37
|
+
hot: 'THREADS_TEMP_HOT',
|
|
38
|
+
warm: 'THREADS_TEMP_WARM',
|
|
39
|
+
tepid: 'THREADS_TEMP_TEPID',
|
|
40
|
+
cold: 'THREADS_TEMP_COLD',
|
|
41
|
+
freezing: 'THREADS_TEMP_FREEZING',
|
|
42
|
+
};
|
|
43
|
+
// Current active thresholds (mutable, can be configured at runtime)
|
|
44
|
+
let currentConfig = { ...exports.DEFAULT_TEMPERATURE_THRESHOLDS };
|
|
45
|
+
/**
|
|
46
|
+
* Build threshold array from config object.
|
|
47
|
+
*/
|
|
48
|
+
function buildThresholds(config) {
|
|
49
|
+
return [
|
|
50
|
+
{ maxDays: config.hot, temperature: 'hot' },
|
|
51
|
+
{ maxDays: config.warm, temperature: 'warm' },
|
|
52
|
+
{ maxDays: config.tepid, temperature: 'tepid' },
|
|
53
|
+
{ maxDays: config.cold, temperature: 'cold' },
|
|
54
|
+
{ maxDays: config.freezing, temperature: 'freezing' },
|
|
55
|
+
{ maxDays: Infinity, temperature: 'frozen' },
|
|
56
|
+
];
|
|
57
|
+
}
|
|
58
|
+
/**
|
|
59
|
+
* Get thresholds from environment variables.
|
|
60
|
+
* Returns only the values that are set.
|
|
61
|
+
*/
|
|
62
|
+
function getThresholdsFromEnv() {
|
|
63
|
+
const result = {};
|
|
64
|
+
for (const [key, envVar] of Object.entries(exports.TEMPERATURE_ENV_VARS)) {
|
|
65
|
+
const value = process.env[envVar];
|
|
66
|
+
if (value !== undefined) {
|
|
67
|
+
const parsed = parseInt(value, 10);
|
|
68
|
+
if (!isNaN(parsed) && parsed > 0) {
|
|
69
|
+
result[key] = parsed;
|
|
70
|
+
}
|
|
71
|
+
}
|
|
72
|
+
}
|
|
73
|
+
return result;
|
|
74
|
+
}
|
|
75
|
+
/**
|
|
76
|
+
* Configure temperature thresholds.
|
|
77
|
+
* Call this at application startup after loading config.
|
|
78
|
+
*
|
|
79
|
+
* Priority: defaults < env vars < config file
|
|
80
|
+
*
|
|
81
|
+
* @param fileConfig - Thresholds from config file (highest priority)
|
|
82
|
+
*/
|
|
83
|
+
function configureTemperatureThresholds(fileConfig) {
|
|
84
|
+
const envConfig = getThresholdsFromEnv();
|
|
85
|
+
currentConfig = {
|
|
86
|
+
...exports.DEFAULT_TEMPERATURE_THRESHOLDS,
|
|
87
|
+
...envConfig,
|
|
88
|
+
...fileConfig,
|
|
89
|
+
};
|
|
90
|
+
}
|
|
91
|
+
/**
|
|
92
|
+
* Get the current temperature threshold configuration.
|
|
93
|
+
*/
|
|
94
|
+
function getTemperatureThresholds() {
|
|
95
|
+
return { ...currentConfig };
|
|
96
|
+
}
|
|
97
|
+
/**
|
|
98
|
+
* Reset thresholds to defaults (useful for testing).
|
|
99
|
+
*/
|
|
100
|
+
function resetTemperatureThresholds() {
|
|
101
|
+
currentConfig = { ...exports.DEFAULT_TEMPERATURE_THRESHOLDS };
|
|
102
|
+
}
|
|
103
|
+
/**
|
|
104
|
+
* Current thresholds array (for backward compatibility).
|
|
105
|
+
* Note: This is now computed dynamically from currentConfig.
|
|
106
|
+
*/
|
|
107
|
+
exports.TEMPERATURE_THRESHOLDS = buildThresholds(exports.DEFAULT_TEMPERATURE_THRESHOLDS);
|
|
108
|
+
/**
|
|
109
|
+
* Temperature ordering from hottest to coldest.
|
|
110
|
+
* Useful for sorting and comparison.
|
|
111
|
+
*/
|
|
112
|
+
exports.TEMPERATURE_ORDER = ['hot', 'warm', 'tepid', 'cold', 'freezing', 'frozen'];
|
|
113
|
+
/**
|
|
114
|
+
* Count business days (Mon-Fri) between two dates.
|
|
115
|
+
* Excludes weekends (Saturday = 6, Sunday = 0).
|
|
116
|
+
*
|
|
117
|
+
* @param from - Start date (earlier)
|
|
118
|
+
* @param to - End date (later, typically now)
|
|
119
|
+
* @returns Number of business days elapsed
|
|
120
|
+
*/
|
|
121
|
+
function countBusinessDays(from, to) {
|
|
122
|
+
// Normalize to start of day to avoid partial day issues
|
|
123
|
+
const start = new Date(from.getFullYear(), from.getMonth(), from.getDate());
|
|
124
|
+
const end = new Date(to.getFullYear(), to.getMonth(), to.getDate());
|
|
125
|
+
// If dates are the same or from is after to, return 0
|
|
126
|
+
if (start >= end) {
|
|
127
|
+
return 0;
|
|
128
|
+
}
|
|
129
|
+
let businessDays = 0;
|
|
130
|
+
const current = new Date(start);
|
|
131
|
+
while (current < end) {
|
|
132
|
+
const dayOfWeek = current.getDay();
|
|
133
|
+
// Skip Saturday (6) and Sunday (0)
|
|
134
|
+
if (dayOfWeek !== 0 && dayOfWeek !== 6) {
|
|
135
|
+
businessDays++;
|
|
136
|
+
}
|
|
137
|
+
current.setDate(current.getDate() + 1);
|
|
138
|
+
}
|
|
139
|
+
return businessDays;
|
|
140
|
+
}
|
|
141
|
+
/**
|
|
142
|
+
* Compute temperature from updatedAt timestamp.
|
|
143
|
+
* Uses business days (Mon-Fri) for calculation.
|
|
144
|
+
*
|
|
145
|
+
* @param updatedAt - ISO timestamp of last update
|
|
146
|
+
* @param now - Current time (injectable for testing)
|
|
147
|
+
* @returns Computed temperature based on recency in business days
|
|
148
|
+
*/
|
|
149
|
+
function computeTemperature(updatedAt, now = new Date()) {
|
|
150
|
+
const updatedDate = new Date(updatedAt);
|
|
151
|
+
const businessDays = countBusinessDays(updatedDate, now);
|
|
152
|
+
const thresholds = buildThresholds(currentConfig);
|
|
153
|
+
for (const { maxDays, temperature } of thresholds) {
|
|
154
|
+
if (businessDays <= maxDays) {
|
|
155
|
+
return temperature;
|
|
156
|
+
}
|
|
157
|
+
}
|
|
158
|
+
return 'frozen';
|
|
159
|
+
}
|
|
160
|
+
//# sourceMappingURL=temperature.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"temperature.js","sourceRoot":"","sources":["../../src/models/temperature.ts"],"names":[],"mappings":";AAAA;;;;;;;;;;;;GAYG;;;AA2DH,oDAcC;AAUD,wEAUC;AAKD,4DAEC;AAKD,gEAEC;AAsBD,8CAuBC;AAUD,gDAaC;AA/JD;;GAEG;AACU,QAAA,8BAA8B,GAA+B;IACxE,GAAG,EAAE,CAAC,EAAQ,2BAA2B;IACzC,IAAI,EAAE,EAAE,EAAM,6BAA6B;IAC3C,KAAK,EAAE,EAAE,EAAK,6BAA6B;IAC3C,IAAI,EAAE,EAAE,EAAM,wCAAwC;IACtD,QAAQ,EAAE,EAAE,EAAE,+BAA+B;CAC9C,CAAC;AAEF;;GAEG;AACU,QAAA,oBAAoB,GAAG;IAClC,GAAG,EAAE,kBAAkB;IACvB,IAAI,EAAE,mBAAmB;IACzB,KAAK,EAAE,oBAAoB;IAC3B,IAAI,EAAE,mBAAmB;IACzB,QAAQ,EAAE,uBAAuB;CACzB,CAAC;AAEX,oEAAoE;AACpE,IAAI,aAAa,GAA+B,EAAE,GAAG,sCAA8B,EAAE,CAAC;AAEtF;;GAEG;AACH,SAAS,eAAe,CAAC,MAAkC;IACzD,OAAO;QACL,EAAE,OAAO,EAAE,MAAM,CAAC,GAAG,EAAE,WAAW,EAAE,KAAoB,EAAE;QAC1D,EAAE,OAAO,EAAE,MAAM,CAAC,IAAI,EAAE,WAAW,EAAE,MAAqB,EAAE;QAC5D,EAAE,OAAO,EAAE,MAAM,CAAC,KAAK,EAAE,WAAW,EAAE,OAAsB,EAAE;QAC9D,EAAE,OAAO,EAAE,MAAM,CAAC,IAAI,EAAE,WAAW,EAAE,MAAqB,EAAE;QAC5D,EAAE,OAAO,EAAE,MAAM,CAAC,QAAQ,EAAE,WAAW,EAAE,UAAyB,EAAE;QACpE,EAAE,OAAO,EAAE,QAAQ,EAAE,WAAW,EAAE,QAAuB,EAAE;KAC5D,CAAC;AACJ,CAAC;AAED;;;GAGG;AACH,SAAgB,oBAAoB;IAClC,MAAM,MAAM,GAAwC,EAAE,CAAC;IAEvD,KAAK,MAAM,CAAC,GAAG,EAAE,MAAM,CAAC,IAAI,MAAM,CAAC,OAAO,CAAC,4BAAoB,CAAC,EAAE,CAAC;QACjE,MAAM,KAAK,GAAG,OAAO,CAAC,GAAG,CAAC,MAAM,CAAC,CAAC;QAClC,IAAI,KAAK,KAAK,SAAS,EAAE,CAAC;YACxB,MAAM,MAAM,GAAG,QAAQ,CAAC,KAAK,EAAE,EAAE,CAAC,CAAC;YACnC,IAAI,CAAC,KAAK,CAAC,MAAM,CAAC,IAAI,MAAM,GAAG,CAAC,EAAE,CAAC;gBACjC,MAAM,CAAC,GAAuC,CAAC,GAAG,MAAM,CAAC;YAC3D,CAAC;QACH,CAAC;IACH,CAAC;IAED,OAAO,MAAM,CAAC;AAChB,CAAC;AAED;;;;;;;GAOG;AACH,SAAgB,8BAA8B,CAC5C,UAAgD;IAEhD,MAAM,SAAS,GAAG,oBAAoB,EAAE,CAAC;IAEzC,aAAa,GAAG;QACd,GAAG,sCAA8B;QACjC,GAAG,SAAS;QACZ,GAAG,UAAU;KACd,CAAC;AACJ,CAAC;AAED;;GAEG;AACH,SAAgB,wBAAwB;IACtC,OAAO,EAAE,GAAG,aAAa,EAAE,CAAC;AAC9B,CAAC;AAED;;GAEG;AACH,SAAgB,0BAA0B;IACxC,aAAa,GAAG,EAAE,GAAG,sCAA8B,EAAE,CAAC;AACxD,CAAC;AAED;;;GAGG;AACU,QAAA,sBAAsB,GAAG,eAAe,CAAC,sCAA8B,CAAC,CAAC;AAEtF;;;GAGG;AACU,QAAA,iBAAiB,GAAkB,CAAC,KAAK,EAAE,MAAM,EAAE,OAAO,EAAE,MAAM,EAAE,UAAU,EAAE,QAAQ,CAAC,CAAC;AAEvG;;;;;;;GAOG;AACH,SAAgB,iBAAiB,CAAC,IAAU,EAAE,EAAQ;IACpD,wDAAwD;IACxD,MAAM,KAAK,GAAG,IAAI,IAAI,CAAC,IAAI,CAAC,WAAW,EAAE,EAAE,IAAI,CAAC,QAAQ,EAAE,EAAE,IAAI,CAAC,OAAO,EAAE,CAAC,CAAC;IAC5E,MAAM,GAAG,GAAG,IAAI,IAAI,CAAC,EAAE,CAAC,WAAW,EAAE,EAAE,EAAE,CAAC,QAAQ,EAAE,EAAE,EAAE,CAAC,OAAO,EAAE,CAAC,CAAC;IAEpE,sDAAsD;IACtD,IAAI,KAAK,IAAI,GAAG,EAAE,CAAC;QACjB,OAAO,CAAC,CAAC;IACX,CAAC;IAED,IAAI,YAAY,GAAG,CAAC,CAAC;IACrB,MAAM,OAAO,GAAG,IAAI,IAAI,CAAC,KAAK,CAAC,CAAC;IAEhC,OAAO,OAAO,GAAG,GAAG,EAAE,CAAC;QACrB,MAAM,SAAS,GAAG,OAAO,CAAC,MAAM,EAAE,CAAC;QACnC,mCAAmC;QACnC,IAAI,SAAS,KAAK,CAAC,IAAI,SAAS,KAAK,CAAC,EAAE,CAAC;YACvC,YAAY,EAAE,CAAC;QACjB,CAAC;QACD,OAAO,CAAC,OAAO,CAAC,OAAO,CAAC,OAAO,EAAE,GAAG,CAAC,CAAC,CAAC;IACzC,CAAC;IAED,OAAO,YAAY,CAAC;AACtB,CAAC;AAED;;;;;;;GAOG;AACH,SAAgB,kBAAkB,CAAC,SAAiB,EAAE,MAAY,IAAI,IAAI,EAAE;IAC1E,MAAM,WAAW,GAAG,IAAI,IAAI,CAAC,SAAS,CAAC,CAAC;IACxC,MAAM,YAAY,GAAG,iBAAiB,CAAC,WAAW,EAAE,GAAG,CAAC,CAAC;IAEzD,MAAM,UAAU,GAAG,eAAe,CAAC,aAAa,CAAC,CAAC;IAElD,KAAK,MAAM,EAAE,OAAO,EAAE,WAAW,EAAE,IAAI,UAAU,EAAE,CAAC;QAClD,IAAI,YAAY,IAAI,OAAO,EAAE,CAAC;YAC5B,OAAO,WAAW,CAAC;QACrB,CAAC;IACH,CAAC;IAED,OAAO,QAAQ,CAAC;AAClB,CAAC"}
|
|
@@ -0,0 +1,102 @@
|
|
|
1
|
+
export type ThreadStatus = 'active' | 'paused' | 'stopped' | 'completed' | 'archived';
|
|
2
|
+
export type Temperature = 'frozen' | 'freezing' | 'cold' | 'tepid' | 'warm' | 'hot';
|
|
3
|
+
export type ThreadSize = 'tiny' | 'small' | 'medium' | 'large' | 'huge';
|
|
4
|
+
export type Importance = 1 | 2 | 3 | 4 | 5;
|
|
5
|
+
export interface ProgressEntry {
|
|
6
|
+
id: string;
|
|
7
|
+
timestamp: string;
|
|
8
|
+
note: string;
|
|
9
|
+
}
|
|
10
|
+
export interface DetailsEntry {
|
|
11
|
+
id: string;
|
|
12
|
+
timestamp: string;
|
|
13
|
+
content: string;
|
|
14
|
+
}
|
|
15
|
+
export interface Dependency {
|
|
16
|
+
threadId: string;
|
|
17
|
+
why: string;
|
|
18
|
+
what: string;
|
|
19
|
+
how: string;
|
|
20
|
+
when: string;
|
|
21
|
+
}
|
|
22
|
+
export type LinkType = 'web' | 'file' | 'thread' | 'custom';
|
|
23
|
+
export interface Link {
|
|
24
|
+
id: string;
|
|
25
|
+
uri: string;
|
|
26
|
+
type: LinkType;
|
|
27
|
+
label?: string;
|
|
28
|
+
description?: string;
|
|
29
|
+
addedAt: string;
|
|
30
|
+
}
|
|
31
|
+
export type Weekday = 'monday' | 'tuesday' | 'wednesday' | 'thursday' | 'friday' | 'saturday' | 'sunday';
|
|
32
|
+
export interface RecurrencePattern {
|
|
33
|
+
interval: number;
|
|
34
|
+
unit: 'day' | 'week' | 'month';
|
|
35
|
+
weekdays?: Weekday[];
|
|
36
|
+
dayOfMonth?: number;
|
|
37
|
+
nthWeekday?: {
|
|
38
|
+
nth: number;
|
|
39
|
+
weekday: Weekday;
|
|
40
|
+
};
|
|
41
|
+
}
|
|
42
|
+
export interface Reminder {
|
|
43
|
+
id: string;
|
|
44
|
+
threadId: string;
|
|
45
|
+
message: string;
|
|
46
|
+
dueAt: string;
|
|
47
|
+
createdAt: string;
|
|
48
|
+
recurrence?: RecurrencePattern;
|
|
49
|
+
dismissedAt?: string;
|
|
50
|
+
lastTriggeredAt?: string;
|
|
51
|
+
}
|
|
52
|
+
export type EntityType = 'thread' | 'container';
|
|
53
|
+
export interface Thread {
|
|
54
|
+
type?: 'thread';
|
|
55
|
+
id: string;
|
|
56
|
+
name: string;
|
|
57
|
+
description: string;
|
|
58
|
+
status: ThreadStatus;
|
|
59
|
+
importance: Importance;
|
|
60
|
+
/** @deprecated Temperature is now derived from lastUpdated. Stored value is ignored. */
|
|
61
|
+
temperature?: Temperature;
|
|
62
|
+
size: ThreadSize;
|
|
63
|
+
parentId: string | null;
|
|
64
|
+
groupId: string | null;
|
|
65
|
+
tags: string[];
|
|
66
|
+
links: Link[];
|
|
67
|
+
reminders: Reminder[];
|
|
68
|
+
dependencies: Dependency[];
|
|
69
|
+
progress: ProgressEntry[];
|
|
70
|
+
details: DetailsEntry[];
|
|
71
|
+
createdAt: string;
|
|
72
|
+
modified: string;
|
|
73
|
+
/** Derived: Latest progress entry timestamp, undefined if no progress. Used for temperature. */
|
|
74
|
+
lastUpdated?: string;
|
|
75
|
+
}
|
|
76
|
+
export interface Container {
|
|
77
|
+
type: 'container';
|
|
78
|
+
id: string;
|
|
79
|
+
name: string;
|
|
80
|
+
description: string;
|
|
81
|
+
parentId: string | null;
|
|
82
|
+
groupId: string | null;
|
|
83
|
+
tags: string[];
|
|
84
|
+
details: DetailsEntry[];
|
|
85
|
+
createdAt: string;
|
|
86
|
+
modified: string;
|
|
87
|
+
}
|
|
88
|
+
export type Entity = Thread | Container;
|
|
89
|
+
export interface Group {
|
|
90
|
+
id: string;
|
|
91
|
+
name: string;
|
|
92
|
+
description: string;
|
|
93
|
+
createdAt: string;
|
|
94
|
+
modified: string;
|
|
95
|
+
}
|
|
96
|
+
export interface ThreadsData {
|
|
97
|
+
threads: Thread[];
|
|
98
|
+
containers: Container[];
|
|
99
|
+
groups: Group[];
|
|
100
|
+
version: string;
|
|
101
|
+
}
|
|
102
|
+
//# sourceMappingURL=types.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"types.d.ts","sourceRoot":"","sources":["../../src/models/types.ts"],"names":[],"mappings":"AACA,MAAM,MAAM,YAAY,GAAG,QAAQ,GAAG,QAAQ,GAAG,SAAS,GAAG,WAAW,GAAG,UAAU,CAAC;AAKtF,MAAM,MAAM,WAAW,GAAG,QAAQ,GAAG,UAAU,GAAG,MAAM,GAAG,OAAO,GAAG,MAAM,GAAG,KAAK,CAAC;AAGpF,MAAM,MAAM,UAAU,GAAG,MAAM,GAAG,OAAO,GAAG,QAAQ,GAAG,OAAO,GAAG,MAAM,CAAC;AAGxE,MAAM,MAAM,UAAU,GAAG,CAAC,GAAG,CAAC,GAAG,CAAC,GAAG,CAAC,GAAG,CAAC,CAAC;AAG3C,MAAM,WAAW,aAAa;IAC5B,EAAE,EAAE,MAAM,CAAC;IACX,SAAS,EAAE,MAAM,CAAC;IAClB,IAAI,EAAE,MAAM,CAAC;CACd;AAGD,MAAM,WAAW,YAAY;IAC3B,EAAE,EAAE,MAAM,CAAC;IACX,SAAS,EAAE,MAAM,CAAC;IAClB,OAAO,EAAE,MAAM,CAAC;CACjB;AAGD,MAAM,WAAW,UAAU;IACzB,QAAQ,EAAE,MAAM,CAAC;IACjB,GAAG,EAAE,MAAM,CAAC;IACZ,IAAI,EAAE,MAAM,CAAC;IACb,GAAG,EAAE,MAAM,CAAC;IACZ,IAAI,EAAE,MAAM,CAAC;CACd;AAGD,MAAM,MAAM,QAAQ,GAAG,KAAK,GAAG,MAAM,GAAG,QAAQ,GAAG,QAAQ,CAAC;AAG5D,MAAM,WAAW,IAAI;IACnB,EAAE,EAAE,MAAM,CAAC;IACX,GAAG,EAAE,MAAM,CAAC;IACZ,IAAI,EAAE,QAAQ,CAAC;IACf,KAAK,CAAC,EAAE,MAAM,CAAC;IACf,WAAW,CAAC,EAAE,MAAM,CAAC;IACrB,OAAO,EAAE,MAAM,CAAC;CACjB;AAKD,MAAM,MAAM,OAAO,GAAG,QAAQ,GAAG,SAAS,GAAG,WAAW,GAAG,UAAU,GAAG,QAAQ,GAAG,UAAU,GAAG,QAAQ,CAAC;AAGzG,MAAM,WAAW,iBAAiB;IAChC,QAAQ,EAAE,MAAM,CAAC;IACjB,IAAI,EAAE,KAAK,GAAG,MAAM,GAAG,OAAO,CAAC;IAC/B,QAAQ,CAAC,EAAE,OAAO,EAAE,CAAC;IACrB,UAAU,CAAC,EAAE,MAAM,CAAC;IACpB,UAAU,CAAC,EAAE;QACX,GAAG,EAAE,MAAM,CAAC;QACZ,OAAO,EAAE,OAAO,CAAC;KAClB,CAAC;CACH;AAGD,MAAM,WAAW,QAAQ;IACvB,EAAE,EAAE,MAAM,CAAC;IACX,QAAQ,EAAE,MAAM,CAAC;IACjB,OAAO,EAAE,MAAM,CAAC;IAChB,KAAK,EAAE,MAAM,CAAC;IACd,SAAS,EAAE,MAAM,CAAC;IAClB,UAAU,CAAC,EAAE,iBAAiB,CAAC;IAC/B,WAAW,CAAC,EAAE,MAAM,CAAC;IACrB,eAAe,CAAC,EAAE,MAAM,CAAC;CAC1B;AAGD,MAAM,MAAM,UAAU,GAAG,QAAQ,GAAG,WAAW,CAAC;AAGhD,MAAM,WAAW,MAAM;IACrB,IAAI,CAAC,EAAE,QAAQ,CAAC;IAChB,EAAE,EAAE,MAAM,CAAC;IACX,IAAI,EAAE,MAAM,CAAC;IACb,WAAW,EAAE,MAAM,CAAC;IACpB,MAAM,EAAE,YAAY,CAAC;IACrB,UAAU,EAAE,UAAU,CAAC;IACvB,wFAAwF;IACxF,WAAW,CAAC,EAAE,WAAW,CAAC;IAC1B,IAAI,EAAE,UAAU,CAAC;IACjB,QAAQ,EAAE,MAAM,GAAG,IAAI,CAAC;IACxB,OAAO,EAAE,MAAM,GAAG,IAAI,CAAC;IACvB,IAAI,EAAE,MAAM,EAAE,CAAC;IACf,KAAK,EAAE,IAAI,EAAE,CAAC;IACd,SAAS,EAAE,QAAQ,EAAE,CAAC;IACtB,YAAY,EAAE,UAAU,EAAE,CAAC;IAC3B,QAAQ,EAAE,aAAa,EAAE,CAAC;IAC1B,OAAO,EAAE,YAAY,EAAE,CAAC;IACxB,SAAS,EAAE,MAAM,CAAC;IAClB,QAAQ,EAAE,MAAM,CAAC;IACjB,gGAAgG;IAChG,WAAW,CAAC,EAAE,MAAM,CAAC;CACtB;AAGD,MAAM,WAAW,SAAS;IACxB,IAAI,EAAE,WAAW,CAAC;IAClB,EAAE,EAAE,MAAM,CAAC;IACX,IAAI,EAAE,MAAM,CAAC;IACb,WAAW,EAAE,MAAM,CAAC;IACpB,QAAQ,EAAE,MAAM,GAAG,IAAI,CAAC;IACxB,OAAO,EAAE,MAAM,GAAG,IAAI,CAAC;IACvB,IAAI,EAAE,MAAM,EAAE,CAAC;IACf,OAAO,EAAE,YAAY,EAAE,CAAC;IACxB,SAAS,EAAE,MAAM,CAAC;IAClB,QAAQ,EAAE,MAAM,CAAC;CAClB;AAGD,MAAM,MAAM,MAAM,GAAG,MAAM,GAAG,SAAS,CAAC;AAGxC,MAAM,WAAW,KAAK;IACpB,EAAE,EAAE,MAAM,CAAC;IACX,IAAI,EAAE,MAAM,CAAC;IACb,WAAW,EAAE,MAAM,CAAC;IACpB,SAAS,EAAE,MAAM,CAAC;IAClB,QAAQ,EAAE,MAAM,CAAC;CAClB;AAGD,MAAM,WAAW,WAAW;IAC1B,OAAO,EAAE,MAAM,EAAE,CAAC;IAClB,UAAU,EAAE,SAAS,EAAE,CAAC;IACxB,MAAM,EAAE,KAAK,EAAE,CAAC;IAChB,OAAO,EAAE,MAAM,CAAC;CACjB"}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"types.js","sourceRoot":"","sources":["../../src/models/types.ts"],"names":[],"mappings":""}
|
package/package.json
ADDED
|
@@ -0,0 +1,54 @@
|
|
|
1
|
+
{
|
|
2
|
+
"name": "@redjay/threads-core",
|
|
3
|
+
"version": "1.1.0",
|
|
4
|
+
"description": "Core types and models for Threads platform",
|
|
5
|
+
"main": "dist/index.js",
|
|
6
|
+
"types": "dist/index.d.ts",
|
|
7
|
+
"exports": {
|
|
8
|
+
".": {
|
|
9
|
+
"types": "./dist/index.d.ts",
|
|
10
|
+
"default": "./dist/index.js"
|
|
11
|
+
},
|
|
12
|
+
"./models": {
|
|
13
|
+
"types": "./dist/models/index.d.ts",
|
|
14
|
+
"default": "./dist/models/index.js"
|
|
15
|
+
}
|
|
16
|
+
},
|
|
17
|
+
"files": [
|
|
18
|
+
"dist",
|
|
19
|
+
"README.md",
|
|
20
|
+
"LICENSE"
|
|
21
|
+
],
|
|
22
|
+
"scripts": {
|
|
23
|
+
"build": "tsc -b",
|
|
24
|
+
"clean": "rm -rf dist",
|
|
25
|
+
"typecheck": "tsc --noEmit"
|
|
26
|
+
},
|
|
27
|
+
"keywords": [
|
|
28
|
+
"threads",
|
|
29
|
+
"types",
|
|
30
|
+
"models"
|
|
31
|
+
],
|
|
32
|
+
"author": "Joshua Ramirez",
|
|
33
|
+
"license": "MIT",
|
|
34
|
+
"engines": {
|
|
35
|
+
"node": ">=20.0.0"
|
|
36
|
+
},
|
|
37
|
+
"repository": {
|
|
38
|
+
"type": "git",
|
|
39
|
+
"url": "git+https://github.com/JoshuaRamirez/threads-cli.git",
|
|
40
|
+
"directory": "packages/core"
|
|
41
|
+
},
|
|
42
|
+
"bugs": {
|
|
43
|
+
"url": "https://github.com/JoshuaRamirez/threads-cli/issues"
|
|
44
|
+
},
|
|
45
|
+
"homepage": "https://github.com/JoshuaRamirez/threads-cli/tree/master/packages/core#readme",
|
|
46
|
+
"publishConfig": {
|
|
47
|
+
"access": "public",
|
|
48
|
+
"registry": "https://registry.npmjs.org/"
|
|
49
|
+
},
|
|
50
|
+
"devDependencies": {
|
|
51
|
+
"@types/node": "^25.0.3",
|
|
52
|
+
"typescript": "^5.9.3"
|
|
53
|
+
}
|
|
54
|
+
}
|