@mrtdown/core 2.0.0-alpha.4 → 2.0.0-alpha.6

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (252) hide show
  1. package/dist/index.d.ts +20 -27
  2. package/dist/index.js +20 -27
  3. package/dist/index.js.map +1 -1
  4. package/dist/schema/Landmark.js.map +1 -1
  5. package/dist/schema/Line.js.map +1 -1
  6. package/dist/schema/Operator.js.map +1 -1
  7. package/dist/schema/Service.js.map +1 -1
  8. package/dist/schema/Station.js.map +1 -1
  9. package/dist/schema/Town.js.map +1 -1
  10. package/dist/schema/common.js.map +1 -1
  11. package/dist/schema/issue/bundle.js.map +1 -1
  12. package/dist/schema/issue/cause.js.map +1 -1
  13. package/dist/schema/issue/claim.js.map +1 -1
  14. package/dist/schema/issue/entity.js.map +1 -1
  15. package/dist/schema/issue/evidence.js +1 -1
  16. package/dist/schema/issue/evidence.js.map +1 -1
  17. package/dist/schema/issue/facilityEffect.js.map +1 -1
  18. package/dist/schema/issue/id.js.map +1 -1
  19. package/dist/schema/issue/impactEvent.js.map +1 -1
  20. package/dist/schema/issue/issue.js +1 -1
  21. package/dist/schema/issue/issue.js.map +1 -1
  22. package/dist/schema/issue/issueType.js.map +1 -1
  23. package/dist/schema/issue/period.js.map +1 -1
  24. package/dist/schema/issue/serviceEffect.js.map +1 -1
  25. package/dist/schema/issue/serviceScope.js.map +1 -1
  26. package/package.json +19 -53
  27. package/README.md +0 -107
  28. package/dist/cli/commands/create.d.ts +0 -30
  29. package/dist/cli/commands/create.js +0 -189
  30. package/dist/cli/commands/create.js.map +0 -1
  31. package/dist/cli/commands/list.d.ts +0 -6
  32. package/dist/cli/commands/list.js +0 -106
  33. package/dist/cli/commands/list.js.map +0 -1
  34. package/dist/cli/commands/show.d.ts +0 -6
  35. package/dist/cli/commands/show.js +0 -156
  36. package/dist/cli/commands/show.js.map +0 -1
  37. package/dist/cli/commands/validate.d.ts +0 -6
  38. package/dist/cli/commands/validate.js +0 -19
  39. package/dist/cli/commands/validate.js.map +0 -1
  40. package/dist/cli/index.d.ts +0 -2
  41. package/dist/cli/index.js +0 -162
  42. package/dist/cli/index.js.map +0 -1
  43. package/dist/constants.d.ts +0 -10
  44. package/dist/constants.js +0 -11
  45. package/dist/constants.js.map +0 -1
  46. package/dist/helpers/calculateDurationWithinServiceHours.d.ts +0 -2
  47. package/dist/helpers/calculateDurationWithinServiceHours.js +0 -13
  48. package/dist/helpers/calculateDurationWithinServiceHours.js.map +0 -1
  49. package/dist/helpers/calculateDurationWithinServiceHours.test.d.ts +0 -1
  50. package/dist/helpers/calculateDurationWithinServiceHours.test.js +0 -83
  51. package/dist/helpers/calculateDurationWithinServiceHours.test.js.map +0 -1
  52. package/dist/helpers/computeImpactFromEvidenceClaims.d.ts +0 -21
  53. package/dist/helpers/computeImpactFromEvidenceClaims.js +0 -293
  54. package/dist/helpers/computeImpactFromEvidenceClaims.js.map +0 -1
  55. package/dist/helpers/computeImpactFromEvidenceClaims.test.d.ts +0 -1
  56. package/dist/helpers/computeImpactFromEvidenceClaims.test.js +0 -544
  57. package/dist/helpers/computeImpactFromEvidenceClaims.test.js.map +0 -1
  58. package/dist/helpers/computeStartOfDaysWithinInterval.d.ts +0 -2
  59. package/dist/helpers/computeStartOfDaysWithinInterval.js +0 -15
  60. package/dist/helpers/computeStartOfDaysWithinInterval.js.map +0 -1
  61. package/dist/helpers/computeStartOfDaysWithinInterval.test.d.ts +0 -1
  62. package/dist/helpers/computeStartOfDaysWithinInterval.test.js +0 -126
  63. package/dist/helpers/computeStartOfDaysWithinInterval.test.js.map +0 -1
  64. package/dist/helpers/estimateOpenAICost.d.ts +0 -40
  65. package/dist/helpers/estimateOpenAICost.js +0 -55
  66. package/dist/helpers/estimateOpenAICost.js.map +0 -1
  67. package/dist/helpers/keyForAffectedEntity.d.ts +0 -7
  68. package/dist/helpers/keyForAffectedEntity.js +0 -14
  69. package/dist/helpers/keyForAffectedEntity.js.map +0 -1
  70. package/dist/helpers/normalizeRecurringPeriod.d.ts +0 -7
  71. package/dist/helpers/normalizeRecurringPeriod.js +0 -118
  72. package/dist/helpers/normalizeRecurringPeriod.js.map +0 -1
  73. package/dist/helpers/normalizeRecurringPeriod.test.d.ts +0 -1
  74. package/dist/helpers/normalizeRecurringPeriod.test.js +0 -93
  75. package/dist/helpers/normalizeRecurringPeriod.test.js.map +0 -1
  76. package/dist/helpers/resolvePeriods.d.ts +0 -224
  77. package/dist/helpers/resolvePeriods.js +0 -207
  78. package/dist/helpers/resolvePeriods.js.map +0 -1
  79. package/dist/helpers/resolvePeriods.test.d.ts +0 -1
  80. package/dist/helpers/resolvePeriods.test.js +0 -239
  81. package/dist/helpers/resolvePeriods.test.js.map +0 -1
  82. package/dist/helpers/splitIntervalByServiceHours.d.ts +0 -2
  83. package/dist/helpers/splitIntervalByServiceHours.js +0 -30
  84. package/dist/helpers/splitIntervalByServiceHours.js.map +0 -1
  85. package/dist/helpers/splitIntervalByServiceHours.test.d.ts +0 -1
  86. package/dist/helpers/splitIntervalByServiceHours.test.js +0 -152
  87. package/dist/helpers/splitIntervalByServiceHours.test.js.map +0 -1
  88. package/dist/helpers/sumIntervalDuration.d.ts +0 -2
  89. package/dist/helpers/sumIntervalDuration.js +0 -9
  90. package/dist/helpers/sumIntervalDuration.js.map +0 -1
  91. package/dist/llm/client.d.ts +0 -2
  92. package/dist/llm/client.js +0 -5
  93. package/dist/llm/client.js.map +0 -1
  94. package/dist/llm/common/MemoryStore.d.ts +0 -21
  95. package/dist/llm/common/MemoryStore.js +0 -100
  96. package/dist/llm/common/MemoryStore.js.map +0 -1
  97. package/dist/llm/common/MemoryStore.test.d.ts +0 -1
  98. package/dist/llm/common/MemoryStore.test.js +0 -225
  99. package/dist/llm/common/MemoryStore.test.js.map +0 -1
  100. package/dist/llm/common/formatCurrentState.d.ts +0 -10
  101. package/dist/llm/common/formatCurrentState.js +0 -342
  102. package/dist/llm/common/formatCurrentState.js.map +0 -1
  103. package/dist/llm/common/tool.d.ts +0 -32
  104. package/dist/llm/common/tool.js +0 -6
  105. package/dist/llm/common/tool.js.map +0 -1
  106. package/dist/llm/functions/extractClaimsFromNewEvidence/eval.test.d.ts +0 -1
  107. package/dist/llm/functions/extractClaimsFromNewEvidence/eval.test.js +0 -433
  108. package/dist/llm/functions/extractClaimsFromNewEvidence/eval.test.js.map +0 -1
  109. package/dist/llm/functions/extractClaimsFromNewEvidence/index.d.ts +0 -18
  110. package/dist/llm/functions/extractClaimsFromNewEvidence/index.js +0 -153
  111. package/dist/llm/functions/extractClaimsFromNewEvidence/index.js.map +0 -1
  112. package/dist/llm/functions/extractClaimsFromNewEvidence/prompt.d.ts +0 -1
  113. package/dist/llm/functions/extractClaimsFromNewEvidence/prompt.js +0 -168
  114. package/dist/llm/functions/extractClaimsFromNewEvidence/prompt.js.map +0 -1
  115. package/dist/llm/functions/extractClaimsFromNewEvidence/tools/FindLinesTool.d.ts +0 -19
  116. package/dist/llm/functions/extractClaimsFromNewEvidence/tools/FindLinesTool.js +0 -65
  117. package/dist/llm/functions/extractClaimsFromNewEvidence/tools/FindLinesTool.js.map +0 -1
  118. package/dist/llm/functions/extractClaimsFromNewEvidence/tools/FindServicesTool.d.ts +0 -21
  119. package/dist/llm/functions/extractClaimsFromNewEvidence/tools/FindServicesTool.js +0 -115
  120. package/dist/llm/functions/extractClaimsFromNewEvidence/tools/FindServicesTool.js.map +0 -1
  121. package/dist/llm/functions/extractClaimsFromNewEvidence/tools/FindStationsTool.d.ts +0 -24
  122. package/dist/llm/functions/extractClaimsFromNewEvidence/tools/FindStationsTool.js +0 -110
  123. package/dist/llm/functions/extractClaimsFromNewEvidence/tools/FindStationsTool.js.map +0 -1
  124. package/dist/llm/functions/generateIssueTitleAndSlug/index.d.ts +0 -14
  125. package/dist/llm/functions/generateIssueTitleAndSlug/index.js +0 -38
  126. package/dist/llm/functions/generateIssueTitleAndSlug/index.js.map +0 -1
  127. package/dist/llm/functions/generateIssueTitleAndSlug/prompt.d.ts +0 -1
  128. package/dist/llm/functions/generateIssueTitleAndSlug/prompt.js +0 -23
  129. package/dist/llm/functions/generateIssueTitleAndSlug/prompt.js.map +0 -1
  130. package/dist/llm/functions/translate/index.d.ts +0 -1
  131. package/dist/llm/functions/translate/index.js +0 -59
  132. package/dist/llm/functions/translate/index.js.map +0 -1
  133. package/dist/llm/functions/triageNewEvidence/eval.test.d.ts +0 -1
  134. package/dist/llm/functions/triageNewEvidence/eval.test.js +0 -139
  135. package/dist/llm/functions/triageNewEvidence/eval.test.js.map +0 -1
  136. package/dist/llm/functions/triageNewEvidence/index.d.ts +0 -37
  137. package/dist/llm/functions/triageNewEvidence/index.js +0 -121
  138. package/dist/llm/functions/triageNewEvidence/index.js.map +0 -1
  139. package/dist/llm/functions/triageNewEvidence/prompt.d.ts +0 -1
  140. package/dist/llm/functions/triageNewEvidence/prompt.js +0 -60
  141. package/dist/llm/functions/triageNewEvidence/prompt.js.map +0 -1
  142. package/dist/llm/functions/triageNewEvidence/tools/FindIssuesTool.d.ts +0 -19
  143. package/dist/llm/functions/triageNewEvidence/tools/FindIssuesTool.js +0 -65
  144. package/dist/llm/functions/triageNewEvidence/tools/FindIssuesTool.js.map +0 -1
  145. package/dist/llm/functions/triageNewEvidence/tools/GetIssueTool.d.ts +0 -19
  146. package/dist/llm/functions/triageNewEvidence/tools/GetIssueTool.js +0 -37
  147. package/dist/llm/functions/triageNewEvidence/tools/GetIssueTool.js.map +0 -1
  148. package/dist/repo/MRTDownRepository.d.ts +0 -23
  149. package/dist/repo/MRTDownRepository.js +0 -28
  150. package/dist/repo/MRTDownRepository.js.map +0 -1
  151. package/dist/repo/common/FileStore.d.ts +0 -12
  152. package/dist/repo/common/FileStore.js +0 -27
  153. package/dist/repo/common/FileStore.js.map +0 -1
  154. package/dist/repo/common/StandardRepository.d.ts +0 -32
  155. package/dist/repo/common/StandardRepository.js +0 -58
  156. package/dist/repo/common/StandardRepository.js.map +0 -1
  157. package/dist/repo/common/store.d.ts +0 -29
  158. package/dist/repo/common/store.js +0 -2
  159. package/dist/repo/common/store.js.map +0 -1
  160. package/dist/repo/issue/IssueRepository.d.ts +0 -36
  161. package/dist/repo/issue/IssueRepository.js +0 -177
  162. package/dist/repo/issue/IssueRepository.js.map +0 -1
  163. package/dist/repo/issue/helpers/deriveCurrentState.d.ts +0 -51
  164. package/dist/repo/issue/helpers/deriveCurrentState.js +0 -113
  165. package/dist/repo/issue/helpers/deriveCurrentState.js.map +0 -1
  166. package/dist/repo/issue/helpers/deriveCurrentState.test.d.ts +0 -1
  167. package/dist/repo/issue/helpers/deriveCurrentState.test.js +0 -477
  168. package/dist/repo/issue/helpers/deriveCurrentState.test.js.map +0 -1
  169. package/dist/repo/landmark/LandmarkRepository.d.ts +0 -7
  170. package/dist/repo/landmark/LandmarkRepository.js +0 -12
  171. package/dist/repo/landmark/LandmarkRepository.js.map +0 -1
  172. package/dist/repo/line/LineRepository.d.ts +0 -13
  173. package/dist/repo/line/LineRepository.js +0 -32
  174. package/dist/repo/line/LineRepository.js.map +0 -1
  175. package/dist/repo/operator/OperatorRepository.d.ts +0 -7
  176. package/dist/repo/operator/OperatorRepository.js +0 -12
  177. package/dist/repo/operator/OperatorRepository.js.map +0 -1
  178. package/dist/repo/service/ServiceRepository.d.ts +0 -19
  179. package/dist/repo/service/ServiceRepository.js +0 -39
  180. package/dist/repo/service/ServiceRepository.js.map +0 -1
  181. package/dist/repo/station/StationRepository.d.ts +0 -13
  182. package/dist/repo/station/StationRepository.js +0 -30
  183. package/dist/repo/station/StationRepository.js.map +0 -1
  184. package/dist/repo/town/TownRepository.d.ts +0 -7
  185. package/dist/repo/town/TownRepository.js +0 -12
  186. package/dist/repo/town/TownRepository.js.map +0 -1
  187. package/dist/scripts/ingestViaWebhook.d.ts +0 -1
  188. package/dist/scripts/ingestViaWebhook.js +0 -9
  189. package/dist/scripts/ingestViaWebhook.js.map +0 -1
  190. package/dist/util/assert.d.ts +0 -1
  191. package/dist/util/assert.js +0 -6
  192. package/dist/util/assert.js.map +0 -1
  193. package/dist/util/ingestContent/helpers/getSlugDateTimeFromClaims.d.ts +0 -7
  194. package/dist/util/ingestContent/helpers/getSlugDateTimeFromClaims.js +0 -24
  195. package/dist/util/ingestContent/helpers/getSlugDateTimeFromClaims.js.map +0 -1
  196. package/dist/util/ingestContent/index.d.ts +0 -12
  197. package/dist/util/ingestContent/index.js +0 -171
  198. package/dist/util/ingestContent/index.js.map +0 -1
  199. package/dist/util/ingestContent/types.d.ts +0 -32
  200. package/dist/util/ingestContent/types.js +0 -2
  201. package/dist/util/ingestContent/types.js.map +0 -1
  202. package/dist/validators/buildContext.d.ts +0 -7
  203. package/dist/validators/buildContext.js +0 -164
  204. package/dist/validators/buildContext.js.map +0 -1
  205. package/dist/validators/index.d.ts +0 -17
  206. package/dist/validators/index.js +0 -58
  207. package/dist/validators/index.js.map +0 -1
  208. package/dist/validators/issue.d.ts +0 -13
  209. package/dist/validators/issue.js +0 -220
  210. package/dist/validators/issue.js.map +0 -1
  211. package/dist/validators/landmark.d.ts +0 -7
  212. package/dist/validators/landmark.js +0 -43
  213. package/dist/validators/landmark.js.map +0 -1
  214. package/dist/validators/line.d.ts +0 -8
  215. package/dist/validators/line.js +0 -87
  216. package/dist/validators/line.js.map +0 -1
  217. package/dist/validators/operator.d.ts +0 -7
  218. package/dist/validators/operator.js +0 -43
  219. package/dist/validators/operator.js.map +0 -1
  220. package/dist/validators/service.d.ts +0 -8
  221. package/dist/validators/service.js +0 -87
  222. package/dist/validators/service.js.map +0 -1
  223. package/dist/validators/station.d.ts +0 -8
  224. package/dist/validators/station.js +0 -93
  225. package/dist/validators/station.js.map +0 -1
  226. package/dist/validators/town.d.ts +0 -7
  227. package/dist/validators/town.js +0 -43
  228. package/dist/validators/town.js.map +0 -1
  229. package/dist/validators/types.d.ts +0 -19
  230. package/dist/validators/types.js +0 -2
  231. package/dist/validators/types.js.map +0 -1
  232. package/dist/validators/utils.d.ts +0 -2
  233. package/dist/validators/utils.js +0 -9
  234. package/dist/validators/utils.js.map +0 -1
  235. package/dist/write/MRTDownWriter.d.ts +0 -27
  236. package/dist/write/MRTDownWriter.js +0 -27
  237. package/dist/write/MRTDownWriter.js.map +0 -1
  238. package/dist/write/common/FileWriteStore.d.ts +0 -13
  239. package/dist/write/common/FileWriteStore.js +0 -31
  240. package/dist/write/common/FileWriteStore.js.map +0 -1
  241. package/dist/write/common/StandardWriter.d.ts +0 -14
  242. package/dist/write/common/StandardWriter.js +0 -17
  243. package/dist/write/common/StandardWriter.js.map +0 -1
  244. package/dist/write/common/store.d.ts +0 -32
  245. package/dist/write/common/store.js +0 -2
  246. package/dist/write/common/store.js.map +0 -1
  247. package/dist/write/id/IdGenerator.d.ts +0 -18
  248. package/dist/write/id/IdGenerator.js +0 -23
  249. package/dist/write/id/IdGenerator.js.map +0 -1
  250. package/dist/write/issue/IssueWriter.d.ts +0 -12
  251. package/dist/write/issue/IssueWriter.js +0 -33
  252. package/dist/write/issue/IssueWriter.js.map +0 -1
@@ -1,239 +0,0 @@
1
- import { describe, expect, test } from 'vitest';
2
- import { resolvePeriods } from './resolvePeriods.js';
3
- describe('resolvePeriods', () => {
4
- const asOf = '2025-01-01T12:00:00+08:00';
5
- const factEndedPeriod = [
6
- {
7
- kind: 'fixed',
8
- startAt: '2025-01-01T08:00:00+08:00',
9
- endAt: '2025-01-01T09:00:00+08:00',
10
- },
11
- ];
12
- test('keeps fact-ended period in all modes', () => {
13
- const canonical = resolvePeriods({
14
- periods: factEndedPeriod,
15
- asOf,
16
- mode: { kind: 'canonical' },
17
- });
18
- const operational = resolvePeriods({
19
- periods: factEndedPeriod,
20
- asOf,
21
- mode: { kind: 'operational' },
22
- });
23
- expect(canonical[0]).toMatchObject({
24
- startAt: '2025-01-01T08:00:00+08:00',
25
- endAt: '2025-01-01T09:00:00+08:00',
26
- endAtResolved: '2025-01-01T09:00:00+08:00',
27
- endAtSource: 'fact',
28
- });
29
- expect(operational[0].endAtSource).toBe('fact');
30
- });
31
- test('open period with no evidence and no crowd remains open', () => {
32
- const result = resolvePeriods({
33
- periods: [
34
- {
35
- kind: 'fixed',
36
- startAt: '2025-01-01T08:00:00+08:00',
37
- endAt: null,
38
- },
39
- ],
40
- asOf,
41
- mode: { kind: 'operational' },
42
- });
43
- expect(result[0]).toMatchObject({
44
- endAt: null,
45
- endAtResolved: null,
46
- endAtSource: 'none',
47
- });
48
- });
49
- test('open period infers end from evidence timeout only', () => {
50
- const result = resolvePeriods({
51
- periods: [
52
- {
53
- kind: 'fixed',
54
- startAt: '2025-01-01T08:00:00+08:00',
55
- endAt: null,
56
- },
57
- ],
58
- asOf: '2025-01-02T01:00:00+08:00', // Past inferred end-of-day (2025-01-02T00:00)
59
- mode: {
60
- kind: 'operational',
61
- lastEvidenceAt: '2025-01-01T09:00:00+08:00',
62
- },
63
- });
64
- expect(result[0]).toMatchObject({
65
- endAtResolved: '2025-01-02T00:00:00.000+08:00',
66
- endAtSource: 'inferred',
67
- endAtReason: 'evidence_timeout',
68
- });
69
- });
70
- test('crowd exited inference wins over evidence timeout', () => {
71
- const result = resolvePeriods({
72
- periods: [
73
- {
74
- kind: 'fixed',
75
- startAt: '2025-01-01T08:00:00+08:00',
76
- endAt: null,
77
- },
78
- ],
79
- asOf: '2025-01-02T01:00:00+08:00', // Past inferred end-of-day (2025-01-02T00:00)
80
- mode: {
81
- kind: 'operational',
82
- lastEvidenceAt: '2025-01-01T09:00:00+08:00',
83
- crowd: {
84
- activeNow: false,
85
- exitedAt: '2025-01-01T10:15:00+08:00',
86
- },
87
- },
88
- });
89
- expect(result[0]).toMatchObject({
90
- endAtResolved: '2025-01-02T00:00:00.000+08:00',
91
- endAtSource: 'inferred',
92
- endAtReason: 'crowd_decay',
93
- });
94
- });
95
- test('crowd.activeNow=true prevents crowd-based inference fallback', () => {
96
- const result = resolvePeriods({
97
- periods: [
98
- {
99
- kind: 'fixed',
100
- startAt: '2025-01-01T08:00:00+08:00',
101
- endAt: null,
102
- },
103
- ],
104
- asOf,
105
- mode: {
106
- kind: 'operational',
107
- crowd: {
108
- activeNow: true,
109
- lastActiveAt: '2025-01-01T09:30:00+08:00',
110
- },
111
- },
112
- });
113
- expect(result[0]).toMatchObject({
114
- endAtResolved: null,
115
- endAtSource: 'none',
116
- });
117
- });
118
- test('clamps inferred end to maxInferredDurationMinutes', () => {
119
- const result = resolvePeriods({
120
- periods: [
121
- {
122
- kind: 'fixed',
123
- startAt: '2025-01-01T08:00:00+08:00',
124
- endAt: null,
125
- },
126
- ],
127
- asOf: '2025-01-02T13:00:00+08:00',
128
- mode: {
129
- kind: 'operational',
130
- lastEvidenceAt: '2025-01-02T10:00:00+08:00',
131
- config: {
132
- maxInferredDurationMinutes: 60,
133
- },
134
- },
135
- });
136
- expect(result[0]).toMatchObject({
137
- endAtResolved: '2025-01-01T09:00:00.000+08:00',
138
- endAtSource: 'inferred',
139
- endAtReason: 'evidence_timeout',
140
- });
141
- });
142
- test('does not close period when inferred end is later than asOf', () => {
143
- const result = resolvePeriods({
144
- periods: [
145
- {
146
- kind: 'fixed',
147
- startAt: '2025-01-01T08:00:00+08:00',
148
- endAt: null,
149
- },
150
- ],
151
- asOf: '2025-01-01T10:00:00+08:00',
152
- mode: {
153
- kind: 'operational',
154
- lastEvidenceAt: '2025-01-01T09:30:00+08:00',
155
- },
156
- });
157
- expect(result[0]).toMatchObject({
158
- endAtResolved: null,
159
- endAtSource: 'none',
160
- });
161
- });
162
- test('expands recurring periods into fixed periods in canonical mode', () => {
163
- const result = resolvePeriods({
164
- periods: [
165
- {
166
- kind: 'recurring',
167
- frequency: 'daily',
168
- startAt: '2025-01-01T00:00:00+08:00',
169
- endAt: '2025-01-03T23:59:59+08:00',
170
- daysOfWeek: null,
171
- timeWindow: {
172
- startAt: '08:00:00',
173
- endAt: '10:00:00',
174
- },
175
- timeZone: 'Asia/Singapore',
176
- excludedDates: null,
177
- },
178
- ],
179
- asOf,
180
- mode: { kind: 'canonical' },
181
- });
182
- expect(result).toEqual([
183
- {
184
- kind: 'fixed',
185
- startAt: '2025-01-01T08:00:00.000+08:00',
186
- endAt: '2025-01-01T10:00:00.000+08:00',
187
- endAtResolved: '2025-01-01T10:00:00.000+08:00',
188
- endAtSource: 'fact',
189
- },
190
- {
191
- kind: 'fixed',
192
- startAt: '2025-01-02T08:00:00.000+08:00',
193
- endAt: '2025-01-02T10:00:00.000+08:00',
194
- endAtResolved: '2025-01-02T10:00:00.000+08:00',
195
- endAtSource: 'fact',
196
- },
197
- {
198
- kind: 'fixed',
199
- startAt: '2025-01-03T08:00:00.000+08:00',
200
- endAt: '2025-01-03T10:00:00.000+08:00',
201
- endAtResolved: '2025-01-03T10:00:00.000+08:00',
202
- endAtSource: 'fact',
203
- },
204
- ]);
205
- });
206
- test('sorts normalized recurring periods together with fixed periods', () => {
207
- const result = resolvePeriods({
208
- periods: [
209
- {
210
- kind: 'fixed',
211
- startAt: '2025-01-01T07:00:00+08:00',
212
- endAt: '2025-01-01T07:30:00+08:00',
213
- },
214
- {
215
- kind: 'recurring',
216
- frequency: 'daily',
217
- startAt: '2025-01-01T00:00:00+08:00',
218
- endAt: '2025-01-02T23:59:59+08:00',
219
- daysOfWeek: null,
220
- timeWindow: {
221
- startAt: '08:00:00',
222
- endAt: '09:00:00',
223
- },
224
- timeZone: 'Asia/Singapore',
225
- excludedDates: null,
226
- },
227
- ],
228
- asOf,
229
- mode: { kind: 'operational' },
230
- });
231
- expect(result.map((period) => period.startAt)).toEqual([
232
- '2025-01-01T07:00:00+08:00',
233
- '2025-01-01T08:00:00.000+08:00',
234
- '2025-01-02T08:00:00.000+08:00',
235
- ]);
236
- expect(result.every((period) => period.endAtSource === 'fact')).toBe(true);
237
- });
238
- });
239
- //# sourceMappingURL=resolvePeriods.test.js.map
@@ -1 +0,0 @@
1
- {"version":3,"file":"resolvePeriods.test.js","sourceRoot":"/","sources":["helpers/resolvePeriods.test.ts"],"names":[],"mappings":"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","sourcesContent":["import { describe, expect, test } from 'vitest';\nimport type { Period } from '#schema/issue/period.js';\nimport { resolvePeriods } from './resolvePeriods.js';\n\ndescribe('resolvePeriods', () => {\n const asOf = '2025-01-01T12:00:00+08:00';\n const factEndedPeriod: Period[] = [\n {\n kind: 'fixed',\n startAt: '2025-01-01T08:00:00+08:00',\n endAt: '2025-01-01T09:00:00+08:00',\n },\n ];\n\n test('keeps fact-ended period in all modes', () => {\n const canonical = resolvePeriods({\n periods: factEndedPeriod,\n asOf,\n mode: { kind: 'canonical' },\n });\n const operational = resolvePeriods({\n periods: factEndedPeriod,\n asOf,\n mode: { kind: 'operational' },\n });\n\n expect(canonical[0]).toMatchObject({\n startAt: '2025-01-01T08:00:00+08:00',\n endAt: '2025-01-01T09:00:00+08:00',\n endAtResolved: '2025-01-01T09:00:00+08:00',\n endAtSource: 'fact',\n });\n expect(operational[0].endAtSource).toBe('fact');\n });\n\n test('open period with no evidence and no crowd remains open', () => {\n const result = resolvePeriods({\n periods: [\n {\n kind: 'fixed',\n startAt: '2025-01-01T08:00:00+08:00',\n endAt: null,\n },\n ],\n asOf,\n mode: { kind: 'operational' },\n });\n\n expect(result[0]).toMatchObject({\n endAt: null,\n endAtResolved: null,\n endAtSource: 'none',\n });\n });\n\n test('open period infers end from evidence timeout only', () => {\n const result = resolvePeriods({\n periods: [\n {\n kind: 'fixed',\n startAt: '2025-01-01T08:00:00+08:00',\n endAt: null,\n },\n ],\n asOf: '2025-01-02T01:00:00+08:00', // Past inferred end-of-day (2025-01-02T00:00)\n mode: {\n kind: 'operational',\n lastEvidenceAt: '2025-01-01T09:00:00+08:00',\n },\n });\n\n expect(result[0]).toMatchObject({\n endAtResolved: '2025-01-02T00:00:00.000+08:00',\n endAtSource: 'inferred',\n endAtReason: 'evidence_timeout',\n });\n });\n\n test('crowd exited inference wins over evidence timeout', () => {\n const result = resolvePeriods({\n periods: [\n {\n kind: 'fixed',\n startAt: '2025-01-01T08:00:00+08:00',\n endAt: null,\n },\n ],\n asOf: '2025-01-02T01:00:00+08:00', // Past inferred end-of-day (2025-01-02T00:00)\n mode: {\n kind: 'operational',\n lastEvidenceAt: '2025-01-01T09:00:00+08:00',\n crowd: {\n activeNow: false,\n exitedAt: '2025-01-01T10:15:00+08:00',\n },\n },\n });\n\n expect(result[0]).toMatchObject({\n endAtResolved: '2025-01-02T00:00:00.000+08:00',\n endAtSource: 'inferred',\n endAtReason: 'crowd_decay',\n });\n });\n\n test('crowd.activeNow=true prevents crowd-based inference fallback', () => {\n const result = resolvePeriods({\n periods: [\n {\n kind: 'fixed',\n startAt: '2025-01-01T08:00:00+08:00',\n endAt: null,\n },\n ],\n asOf,\n mode: {\n kind: 'operational',\n crowd: {\n activeNow: true,\n lastActiveAt: '2025-01-01T09:30:00+08:00',\n },\n },\n });\n\n expect(result[0]).toMatchObject({\n endAtResolved: null,\n endAtSource: 'none',\n });\n });\n\n test('clamps inferred end to maxInferredDurationMinutes', () => {\n const result = resolvePeriods({\n periods: [\n {\n kind: 'fixed',\n startAt: '2025-01-01T08:00:00+08:00',\n endAt: null,\n },\n ],\n asOf: '2025-01-02T13:00:00+08:00',\n mode: {\n kind: 'operational',\n lastEvidenceAt: '2025-01-02T10:00:00+08:00',\n config: {\n maxInferredDurationMinutes: 60,\n },\n },\n });\n\n expect(result[0]).toMatchObject({\n endAtResolved: '2025-01-01T09:00:00.000+08:00',\n endAtSource: 'inferred',\n endAtReason: 'evidence_timeout',\n });\n });\n\n test('does not close period when inferred end is later than asOf', () => {\n const result = resolvePeriods({\n periods: [\n {\n kind: 'fixed',\n startAt: '2025-01-01T08:00:00+08:00',\n endAt: null,\n },\n ],\n asOf: '2025-01-01T10:00:00+08:00',\n mode: {\n kind: 'operational',\n lastEvidenceAt: '2025-01-01T09:30:00+08:00',\n },\n });\n\n expect(result[0]).toMatchObject({\n endAtResolved: null,\n endAtSource: 'none',\n });\n });\n\n test('expands recurring periods into fixed periods in canonical mode', () => {\n const result = resolvePeriods({\n periods: [\n {\n kind: 'recurring',\n frequency: 'daily',\n startAt: '2025-01-01T00:00:00+08:00',\n endAt: '2025-01-03T23:59:59+08:00',\n daysOfWeek: null,\n timeWindow: {\n startAt: '08:00:00',\n endAt: '10:00:00',\n },\n timeZone: 'Asia/Singapore',\n excludedDates: null,\n },\n ],\n asOf,\n mode: { kind: 'canonical' },\n });\n\n expect(result).toEqual([\n {\n kind: 'fixed',\n startAt: '2025-01-01T08:00:00.000+08:00',\n endAt: '2025-01-01T10:00:00.000+08:00',\n endAtResolved: '2025-01-01T10:00:00.000+08:00',\n endAtSource: 'fact',\n },\n {\n kind: 'fixed',\n startAt: '2025-01-02T08:00:00.000+08:00',\n endAt: '2025-01-02T10:00:00.000+08:00',\n endAtResolved: '2025-01-02T10:00:00.000+08:00',\n endAtSource: 'fact',\n },\n {\n kind: 'fixed',\n startAt: '2025-01-03T08:00:00.000+08:00',\n endAt: '2025-01-03T10:00:00.000+08:00',\n endAtResolved: '2025-01-03T10:00:00.000+08:00',\n endAtSource: 'fact',\n },\n ]);\n });\n\n test('sorts normalized recurring periods together with fixed periods', () => {\n const result = resolvePeriods({\n periods: [\n {\n kind: 'fixed',\n startAt: '2025-01-01T07:00:00+08:00',\n endAt: '2025-01-01T07:30:00+08:00',\n },\n {\n kind: 'recurring',\n frequency: 'daily',\n startAt: '2025-01-01T00:00:00+08:00',\n endAt: '2025-01-02T23:59:59+08:00',\n daysOfWeek: null,\n timeWindow: {\n startAt: '08:00:00',\n endAt: '09:00:00',\n },\n timeZone: 'Asia/Singapore',\n excludedDates: null,\n },\n ],\n asOf,\n mode: { kind: 'operational' },\n });\n\n expect(result.map((period) => period.startAt)).toEqual([\n '2025-01-01T07:00:00+08:00',\n '2025-01-01T08:00:00.000+08:00',\n '2025-01-02T08:00:00.000+08:00',\n ]);\n expect(result.every((period) => period.endAtSource === 'fact')).toBe(true);\n });\n});\n"]}
@@ -1,2 +0,0 @@
1
- import { type Interval } from 'luxon';
2
- export declare function splitIntervalByServiceHours(interval: Interval): Interval[];
@@ -1,30 +0,0 @@
1
- import { DateTime } from 'luxon';
2
- import { computeStartOfDaysWithinInterval } from './computeStartOfDaysWithinInterval.js';
3
- import { assert } from '../util/assert.js';
4
- export function splitIntervalByServiceHours(interval) {
5
- assert(interval.start != null);
6
- assert(interval.end != null);
7
- const startOfDaysWithinRange = computeStartOfDaysWithinInterval(interval.start, interval.end);
8
- const segments = [];
9
- for (const segment of interval.splitAt(...startOfDaysWithinRange)) {
10
- const { start, end } = segment;
11
- assert(start != null);
12
- assert(end != null);
13
- const segmentStart = DateTime.max(start, start.set({ hour: 5, minute: 30, second: 0, millisecond: 0 }));
14
- const segmentEnd = DateTime.max(end, segmentStart);
15
- const segmentDuration = segmentEnd.diff(segmentStart);
16
- if (segmentDuration.as('milliseconds') <= 0) {
17
- continue;
18
- }
19
- const segmentUpdated = segment.set({
20
- start: segmentStart,
21
- end: segmentEnd,
22
- });
23
- if (!segmentUpdated.isValid) {
24
- continue;
25
- }
26
- segments.push(segmentUpdated);
27
- }
28
- return segments;
29
- }
30
- //# sourceMappingURL=splitIntervalByServiceHours.js.map
@@ -1 +0,0 @@
1
- {"version":3,"file":"splitIntervalByServiceHours.js","sourceRoot":"/","sources":["helpers/splitIntervalByServiceHours.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,QAAQ,EAAiB,MAAM,OAAO,CAAC;AAChD,OAAO,EAAE,gCAAgC,EAAE,MAAM,uCAAuC,CAAC;AACzF,OAAO,EAAE,MAAM,EAAE,MAAM,mBAAmB,CAAC;AAE3C,MAAM,UAAU,2BAA2B,CAAC,QAAkB;IAC5D,MAAM,CAAC,QAAQ,CAAC,KAAK,IAAI,IAAI,CAAC,CAAC;IAC/B,MAAM,CAAC,QAAQ,CAAC,GAAG,IAAI,IAAI,CAAC,CAAC;IAE7B,MAAM,sBAAsB,GAAG,gCAAgC,CAC7D,QAAQ,CAAC,KAAK,EACd,QAAQ,CAAC,GAAG,CACb,CAAC;IAEF,MAAM,QAAQ,GAAe,EAAE,CAAC;IAEhC,KAAK,MAAM,OAAO,IAAI,QAAQ,CAAC,OAAO,CAAC,GAAG,sBAAsB,CAAC,EAAE,CAAC;QAClE,MAAM,EAAE,KAAK,EAAE,GAAG,EAAE,GAAG,OAAO,CAAC;QAC/B,MAAM,CAAC,KAAK,IAAI,IAAI,CAAC,CAAC;QACtB,MAAM,CAAC,GAAG,IAAI,IAAI,CAAC,CAAC;QAEpB,MAAM,YAAY,GAAG,QAAQ,CAAC,GAAG,CAC/B,KAAK,EACL,KAAK,CAAC,GAAG,CAAC,EAAE,IAAI,EAAE,CAAC,EAAE,MAAM,EAAE,EAAE,EAAE,MAAM,EAAE,CAAC,EAAE,WAAW,EAAE,CAAC,EAAE,CAAC,CAC9D,CAAC;QACF,MAAM,UAAU,GAAG,QAAQ,CAAC,GAAG,CAAC,GAAG,EAAE,YAAY,CAAC,CAAC;QACnD,MAAM,eAAe,GAAG,UAAU,CAAC,IAAI,CAAC,YAAY,CAAC,CAAC;QAEtD,IAAI,eAAe,CAAC,EAAE,CAAC,cAAc,CAAC,IAAI,CAAC,EAAE,CAAC;YAC5C,SAAS;QACX,CAAC;QAED,MAAM,cAAc,GAAG,OAAO,CAAC,GAAG,CAAC;YACjC,KAAK,EAAE,YAAY;YACnB,GAAG,EAAE,UAAU;SAChB,CAAC,CAAC;QAEH,IAAI,CAAC,cAAc,CAAC,OAAO,EAAE,CAAC;YAC5B,SAAS;QACX,CAAC;QAED,QAAQ,CAAC,IAAI,CAAC,cAAc,CAAC,CAAC;IAChC,CAAC;IAED,OAAO,QAAQ,CAAC;AAClB,CAAC","sourcesContent":["import { DateTime, type Interval } from 'luxon';\nimport { computeStartOfDaysWithinInterval } from './computeStartOfDaysWithinInterval.js';\nimport { assert } from '../util/assert.js';\n\nexport function splitIntervalByServiceHours(interval: Interval): Interval[] {\n assert(interval.start != null);\n assert(interval.end != null);\n\n const startOfDaysWithinRange = computeStartOfDaysWithinInterval(\n interval.start,\n interval.end,\n );\n\n const segments: Interval[] = [];\n\n for (const segment of interval.splitAt(...startOfDaysWithinRange)) {\n const { start, end } = segment;\n assert(start != null);\n assert(end != null);\n\n const segmentStart = DateTime.max(\n start,\n start.set({ hour: 5, minute: 30, second: 0, millisecond: 0 }), // Limit to start of general service hours\n );\n const segmentEnd = DateTime.max(end, segmentStart);\n const segmentDuration = segmentEnd.diff(segmentStart);\n\n if (segmentDuration.as('milliseconds') <= 0) {\n continue;\n }\n\n const segmentUpdated = segment.set({\n start: segmentStart,\n end: segmentEnd,\n });\n\n if (!segmentUpdated.isValid) {\n continue;\n }\n\n segments.push(segmentUpdated);\n }\n\n return segments;\n}\n"]}
@@ -1 +0,0 @@
1
- export {};
@@ -1,152 +0,0 @@
1
- import { describe, expect, test } from 'vitest';
2
- import { DateTime, Interval } from 'luxon';
3
- import { splitIntervalByServiceHours } from './splitIntervalByServiceHours.js';
4
- describe('splitIntervalByServiceHours', () => {
5
- test('single day, within service hours', () => {
6
- expect(splitIntervalByServiceHours(Interval.fromDateTimes(DateTime.fromObject({
7
- day: 1,
8
- month: 4,
9
- year: 2025,
10
- hour: 8,
11
- minute: 0,
12
- }), DateTime.fromObject({
13
- day: 1,
14
- month: 4,
15
- year: 2025,
16
- hour: 12,
17
- minute: 30,
18
- })))).toEqual([
19
- Interval.fromDateTimes(DateTime.fromObject({
20
- day: 1,
21
- month: 4,
22
- year: 2025,
23
- hour: 8,
24
- minute: 0,
25
- }), DateTime.fromObject({
26
- day: 1,
27
- month: 4,
28
- year: 2025,
29
- hour: 12,
30
- minute: 30,
31
- })),
32
- ]);
33
- });
34
- describe('transcends service hour boundaries', () => {
35
- test('single day, starts before service hours', () => {
36
- expect(splitIntervalByServiceHours(Interval.fromDateTimes(DateTime.fromObject({
37
- day: 1,
38
- month: 4,
39
- year: 2025,
40
- hour: 5,
41
- minute: 0,
42
- }), DateTime.fromObject({
43
- day: 1,
44
- month: 4,
45
- year: 2025,
46
- hour: 6,
47
- minute: 0,
48
- })))).toEqual([
49
- Interval.fromDateTimes(DateTime.fromObject({
50
- day: 1,
51
- month: 4,
52
- year: 2025,
53
- hour: 5,
54
- minute: 30,
55
- }), DateTime.fromObject({
56
- day: 1,
57
- month: 4,
58
- year: 2025,
59
- hour: 6,
60
- minute: 0,
61
- })),
62
- ]);
63
- });
64
- test('single day, ends after service hours', () => {
65
- expect(splitIntervalByServiceHours(Interval.fromDateTimes(DateTime.fromObject({
66
- day: 1,
67
- month: 4,
68
- year: 2025,
69
- hour: 18,
70
- minute: 0,
71
- }), DateTime.fromObject({
72
- day: 2,
73
- month: 4,
74
- year: 2025,
75
- hour: 1,
76
- minute: 0,
77
- })))).toEqual([
78
- Interval.fromDateTimes(DateTime.fromObject({
79
- day: 1,
80
- month: 4,
81
- year: 2025,
82
- hour: 18,
83
- minute: 0,
84
- }), DateTime.fromObject({
85
- day: 2,
86
- month: 4,
87
- year: 2025,
88
- hour: 0,
89
- minute: 0,
90
- })),
91
- ]);
92
- });
93
- test('multiple days, transcends multiple service hours/non services hour ranges', () => {
94
- expect(splitIntervalByServiceHours(Interval.fromDateTimes(DateTime.fromObject({
95
- day: 1,
96
- month: 4,
97
- year: 2025,
98
- hour: 18,
99
- minute: 0,
100
- }), DateTime.fromObject({
101
- day: 2,
102
- month: 4,
103
- year: 2025,
104
- hour: 18,
105
- minute: 0,
106
- })))).toEqual([
107
- Interval.fromDateTimes(DateTime.fromObject({
108
- day: 1,
109
- month: 4,
110
- year: 2025,
111
- hour: 18,
112
- minute: 0,
113
- }), DateTime.fromObject({
114
- day: 2,
115
- month: 4,
116
- year: 2025,
117
- hour: 0,
118
- minute: 0,
119
- })),
120
- Interval.fromDateTimes(DateTime.fromObject({
121
- day: 2,
122
- month: 4,
123
- year: 2025,
124
- hour: 5,
125
- minute: 30,
126
- }), DateTime.fromObject({
127
- day: 2,
128
- month: 4,
129
- year: 2025,
130
- hour: 18,
131
- minute: 0,
132
- })),
133
- ]);
134
- });
135
- });
136
- test('outside service hours', () => {
137
- expect(splitIntervalByServiceHours(Interval.fromDateTimes(DateTime.fromObject({
138
- day: 1,
139
- month: 4,
140
- year: 2025,
141
- hour: 3,
142
- minute: 0,
143
- }), DateTime.fromObject({
144
- day: 1,
145
- month: 4,
146
- year: 2025,
147
- hour: 4,
148
- minute: 30,
149
- })))).toEqual([]);
150
- });
151
- });
152
- //# sourceMappingURL=splitIntervalByServiceHours.test.js.map
@@ -1 +0,0 @@
1
- {"version":3,"file":"splitIntervalByServiceHours.test.js","sourceRoot":"/","sources":["helpers/splitIntervalByServiceHours.test.ts"],"names":[],"mappings":"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","sourcesContent":["import { describe, expect, test } from 'vitest';\nimport { DateTime, Interval } from 'luxon';\nimport { splitIntervalByServiceHours } from './splitIntervalByServiceHours.js';\n\ndescribe('splitIntervalByServiceHours', () => {\n test('single day, within service hours', () => {\n expect(\n splitIntervalByServiceHours(\n Interval.fromDateTimes(\n DateTime.fromObject({\n day: 1,\n month: 4,\n year: 2025,\n hour: 8,\n minute: 0,\n }),\n DateTime.fromObject({\n day: 1,\n month: 4,\n year: 2025,\n hour: 12,\n minute: 30,\n }),\n ),\n ),\n ).toEqual([\n Interval.fromDateTimes(\n DateTime.fromObject({\n day: 1,\n month: 4,\n year: 2025,\n hour: 8,\n minute: 0,\n }),\n DateTime.fromObject({\n day: 1,\n month: 4,\n year: 2025,\n hour: 12,\n minute: 30,\n }),\n ),\n ] satisfies Interval[]);\n });\n describe('transcends service hour boundaries', () => {\n test('single day, starts before service hours', () => {\n expect(\n splitIntervalByServiceHours(\n Interval.fromDateTimes(\n DateTime.fromObject({\n day: 1,\n month: 4,\n year: 2025,\n hour: 5,\n minute: 0,\n }),\n DateTime.fromObject({\n day: 1,\n month: 4,\n year: 2025,\n hour: 6,\n minute: 0,\n }),\n ),\n ),\n ).toEqual([\n Interval.fromDateTimes(\n DateTime.fromObject({\n day: 1,\n month: 4,\n year: 2025,\n hour: 5,\n minute: 30,\n }),\n DateTime.fromObject({\n day: 1,\n month: 4,\n year: 2025,\n hour: 6,\n minute: 0,\n }),\n ),\n ] satisfies Interval[]);\n });\n test('single day, ends after service hours', () => {\n expect(\n splitIntervalByServiceHours(\n Interval.fromDateTimes(\n DateTime.fromObject({\n day: 1,\n month: 4,\n year: 2025,\n hour: 18,\n minute: 0,\n }),\n DateTime.fromObject({\n day: 2,\n month: 4,\n year: 2025,\n hour: 1,\n minute: 0,\n }),\n ),\n ),\n ).toEqual([\n Interval.fromDateTimes(\n DateTime.fromObject({\n day: 1,\n month: 4,\n year: 2025,\n hour: 18,\n minute: 0,\n }),\n DateTime.fromObject({\n day: 2,\n month: 4,\n year: 2025,\n hour: 0,\n minute: 0,\n }),\n ),\n ] satisfies Interval[]);\n });\n test('multiple days, transcends multiple service hours/non services hour ranges', () => {\n expect(\n splitIntervalByServiceHours(\n Interval.fromDateTimes(\n DateTime.fromObject({\n day: 1,\n month: 4,\n year: 2025,\n hour: 18,\n minute: 0,\n }),\n DateTime.fromObject({\n day: 2,\n month: 4,\n year: 2025,\n hour: 18,\n minute: 0,\n }),\n ),\n ),\n ).toEqual([\n Interval.fromDateTimes(\n DateTime.fromObject({\n day: 1,\n month: 4,\n year: 2025,\n hour: 18,\n minute: 0,\n }),\n DateTime.fromObject({\n day: 2,\n month: 4,\n year: 2025,\n hour: 0,\n minute: 0,\n }),\n ),\n Interval.fromDateTimes(\n DateTime.fromObject({\n day: 2,\n month: 4,\n year: 2025,\n hour: 5,\n minute: 30,\n }),\n DateTime.fromObject({\n day: 2,\n month: 4,\n year: 2025,\n hour: 18,\n minute: 0,\n }),\n ),\n ] satisfies Interval[]);\n });\n });\n test('outside service hours', () => {\n expect(\n splitIntervalByServiceHours(\n Interval.fromDateTimes(\n DateTime.fromObject({\n day: 1,\n month: 4,\n year: 2025,\n hour: 3,\n minute: 0,\n }),\n DateTime.fromObject({\n day: 1,\n month: 4,\n year: 2025,\n hour: 4,\n minute: 30,\n }),\n ),\n ),\n ).toEqual([] satisfies Interval[]);\n });\n});\n"]}
@@ -1,2 +0,0 @@
1
- import { Duration, type Interval } from 'luxon';
2
- export declare function sumIntervalDuration(intervals: Interval[]): Duration<true>;
@@ -1,9 +0,0 @@
1
- import { Duration } from 'luxon';
2
- export function sumIntervalDuration(intervals) {
3
- let duration = Duration.fromObject({ milliseconds: 0 });
4
- for (const segment of intervals) {
5
- duration = duration.plus(segment.toDuration());
6
- }
7
- return duration;
8
- }
9
- //# sourceMappingURL=sumIntervalDuration.js.map
@@ -1 +0,0 @@
1
- {"version":3,"file":"sumIntervalDuration.js","sourceRoot":"/","sources":["helpers/sumIntervalDuration.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,QAAQ,EAAiB,MAAM,OAAO,CAAC;AAEhD,MAAM,UAAU,mBAAmB,CAAC,SAAqB;IACvD,IAAI,QAAQ,GAAG,QAAQ,CAAC,UAAU,CAAC,EAAE,YAAY,EAAE,CAAC,EAAE,CAAC,CAAC;IACxD,KAAK,MAAM,OAAO,IAAI,SAAS,EAAE,CAAC;QAChC,QAAQ,GAAG,QAAQ,CAAC,IAAI,CAAC,OAAO,CAAC,UAAU,EAAE,CAAC,CAAC;IACjD,CAAC;IACD,OAAO,QAAQ,CAAC;AAClB,CAAC","sourcesContent":["import { Duration, type Interval } from 'luxon';\n\nexport function sumIntervalDuration(intervals: Interval[]) {\n let duration = Duration.fromObject({ milliseconds: 0 });\n for (const segment of intervals) {\n duration = duration.plus(segment.toDuration());\n }\n return duration;\n}\n"]}
@@ -1,2 +0,0 @@
1
- import OpenAI from 'openai';
2
- export declare const openAiClient: OpenAI;
@@ -1,5 +0,0 @@
1
- import OpenAI from 'openai';
2
- export const openAiClient = new OpenAI({
3
- apiKey: process.env.OPENAI_AI_KEY,
4
- });
5
- //# sourceMappingURL=client.js.map
@@ -1 +0,0 @@
1
- {"version":3,"file":"client.js","sourceRoot":"/","sources":["llm/client.ts"],"names":[],"mappings":"AAAA,OAAO,MAAM,MAAM,QAAQ,CAAC;AAE5B,MAAM,CAAC,MAAM,YAAY,GAAG,IAAI,MAAM,CAAC;IACrC,MAAM,EAAE,OAAO,CAAC,GAAG,CAAC,aAAa;CAClC,CAAC,CAAC","sourcesContent":["import OpenAI from 'openai';\n\nexport const openAiClient = new OpenAI({\n apiKey: process.env.OPENAI_AI_KEY,\n});\n"]}
@@ -1,21 +0,0 @@
1
- import type { IStore } from '#repo/common/store.js';
2
- import type { IWriteStore } from '#write/common/store.js';
3
- export declare class MemoryStore implements IStore, IWriteStore {
4
- private readonly files;
5
- private readonly dirs;
6
- constructor(seed?: {
7
- files?: Record<string, string>;
8
- });
9
- private toStorePath;
10
- exists(path: string): boolean;
11
- readText(path: string): string;
12
- readJson<T>(path: string): T;
13
- listDir(path: string): string[];
14
- ensureDir(path: string): void;
15
- private addChild;
16
- writeText(path: string, text: string): void;
17
- writeJson(path: string, json: unknown): void;
18
- appendText(path: string, text: string): void;
19
- delete(path: string): void;
20
- dumpFiles(): Record<string, string>;
21
- }
@@ -1,100 +0,0 @@
1
- import { basename, dirname, normalize } from 'node:path';
2
- export class MemoryStore {
3
- files = new Map();
4
- dirs = new Map();
5
- constructor(seed) {
6
- // Root dir
7
- this.dirs.set('', new Set());
8
- if (seed?.files) {
9
- for (const [path, text] of Object.entries(seed.files)) {
10
- this.writeText(path, text);
11
- }
12
- }
13
- }
14
- // --------- IStore ---------
15
- toStorePath(path) {
16
- const p = normalize(path);
17
- return p === '.' ? '' : p;
18
- }
19
- exists(path) {
20
- const p = this.toStorePath(path);
21
- return this.files.has(p) || this.dirs.has(p);
22
- }
23
- readText(path) {
24
- const p = this.toStorePath(path);
25
- const v = this.files.get(p);
26
- if (v == null) {
27
- throw new Error(`MemoryStore: File not found: ${path}`);
28
- }
29
- return v;
30
- }
31
- readJson(path) {
32
- return JSON.parse(this.readText(path));
33
- }
34
- listDir(path) {
35
- const p = this.toStorePath(path);
36
- const children = this.dirs.get(p);
37
- if (children == null) {
38
- throw new Error(`MemoryStore: Directory not found: ${path}`);
39
- }
40
- return Array.from(children.values()).sort();
41
- }
42
- // --------- IWriteStore ---------
43
- ensureDir(path) {
44
- const p = this.toStorePath(path);
45
- if (this.dirs.has(p)) {
46
- return;
47
- }
48
- // Ensure parents (dirname returns '.' for root, treat as '')
49
- const rawParent = dirname(p === '' ? '.' : p);
50
- const parent = rawParent === '.' ? '' : rawParent;
51
- if (parent !== '') {
52
- this.ensureDir(parent);
53
- }
54
- // Create this directory
55
- this.dirs.set(p, new Set());
56
- // Register in parent (including root when parent is '')
57
- this.addChild(parent, basename(p));
58
- }
59
- addChild(dir, child) {
60
- const d = this.toStorePath(dir);
61
- const set = this.dirs.get(d);
62
- if (set == null) {
63
- this.ensureDir(d);
64
- this.addChild(d, child);
65
- return;
66
- }
67
- set.add(child);
68
- }
69
- writeText(path, text) {
70
- const p = this.toStorePath(path);
71
- this.ensureDir(dirname(p));
72
- this.addChild(dirname(p), basename(p));
73
- this.files.set(p, text);
74
- }
75
- writeJson(path, json) {
76
- this.writeText(path, JSON.stringify(json));
77
- }
78
- appendText(path, text) {
79
- const p = this.toStorePath(path);
80
- this.ensureDir(dirname(p));
81
- this.addChild(dirname(p), basename(p));
82
- const prevContent = this.files.get(p) ?? '';
83
- this.files.set(p, prevContent + text);
84
- }
85
- delete(path) {
86
- const p = this.toStorePath(path);
87
- this.files.delete(p);
88
- this.dirs.delete(p);
89
- this.dirs.delete(path);
90
- }
91
- // Debug helpers
92
- dumpFiles() {
93
- const result = {};
94
- for (const [path, text] of this.files.entries()) {
95
- result[path] = text;
96
- }
97
- return result;
98
- }
99
- }
100
- //# sourceMappingURL=MemoryStore.js.map
@@ -1 +0,0 @@
1
- {"version":3,"file":"MemoryStore.js","sourceRoot":"/","sources":["llm/common/MemoryStore.ts"],"names":[],"mappings":"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","sourcesContent":["import { basename, dirname, normalize } from 'node:path';\nimport type { IStore } from '#repo/common/store.js';\nimport type { IWriteStore } from '#write/common/store.js';\n\nexport class MemoryStore implements IStore, IWriteStore {\n private readonly files = new Map<string, string>();\n private readonly dirs = new Map<string, Set<string>>();\n\n constructor(seed?: { files?: Record<string, string> }) {\n // Root dir\n this.dirs.set('', new Set());\n\n if (seed?.files) {\n for (const [path, text] of Object.entries(seed.files)) {\n this.writeText(path, text);\n }\n }\n }\n\n // --------- IStore ---------\n private toStorePath(path: string): string {\n const p = normalize(path);\n return p === '.' ? '' : p;\n }\n\n exists(path: string): boolean {\n const p = this.toStorePath(path);\n return this.files.has(p) || this.dirs.has(p);\n }\n\n readText(path: string): string {\n const p = this.toStorePath(path);\n const v = this.files.get(p);\n if (v == null) {\n throw new Error(`MemoryStore: File not found: ${path}`);\n }\n return v;\n }\n\n readJson<T>(path: string): T {\n return JSON.parse(this.readText(path));\n }\n\n listDir(path: string): string[] {\n const p = this.toStorePath(path);\n const children = this.dirs.get(p);\n if (children == null) {\n throw new Error(`MemoryStore: Directory not found: ${path}`);\n }\n return Array.from(children.values()).sort();\n }\n\n // --------- IWriteStore ---------\n ensureDir(path: string): void {\n const p = this.toStorePath(path);\n if (this.dirs.has(p)) {\n return;\n }\n\n // Ensure parents (dirname returns '.' for root, treat as '')\n const rawParent = dirname(p === '' ? '.' : p);\n const parent = rawParent === '.' ? '' : rawParent;\n if (parent !== '') {\n this.ensureDir(parent);\n }\n\n // Create this directory\n this.dirs.set(p, new Set());\n\n // Register in parent (including root when parent is '')\n this.addChild(parent, basename(p));\n }\n\n private addChild(dir: string, child: string): void {\n const d = this.toStorePath(dir);\n const set = this.dirs.get(d);\n if (set == null) {\n this.ensureDir(d);\n this.addChild(d, child);\n return;\n }\n set.add(child);\n }\n\n writeText(path: string, text: string): void {\n const p = this.toStorePath(path);\n this.ensureDir(dirname(p));\n this.addChild(dirname(p), basename(p));\n this.files.set(p, text);\n }\n\n writeJson(path: string, json: unknown): void {\n this.writeText(path, JSON.stringify(json));\n }\n\n appendText(path: string, text: string): void {\n const p = this.toStorePath(path);\n this.ensureDir(dirname(p));\n this.addChild(dirname(p), basename(p));\n const prevContent = this.files.get(p) ?? '';\n this.files.set(p, prevContent + text);\n }\n\n delete(path: string): void {\n const p = this.toStorePath(path);\n this.files.delete(p);\n this.dirs.delete(p);\n this.dirs.delete(path);\n }\n\n // Debug helpers\n dumpFiles(): Record<string, string> {\n const result: Record<string, string> = {};\n for (const [path, text] of this.files.entries()) {\n result[path] = text;\n }\n return result;\n }\n}\n"]}