@knpkv/jira-clockify 1.2.1 → 1.4.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.
Files changed (243) hide show
  1. package/README.md +254 -3
  2. package/dist/package.json +36 -12
  3. package/dist/src/agent/agentSettings.d.ts +18 -0
  4. package/dist/src/agent/agentSettings.d.ts.map +1 -0
  5. package/dist/src/agent/agentSettings.js +23 -0
  6. package/dist/src/agent/agentSettings.js.map +1 -0
  7. package/dist/src/agent/schedule.d.ts +20 -0
  8. package/dist/src/agent/schedule.d.ts.map +1 -0
  9. package/dist/src/agent/schedule.js +189 -0
  10. package/dist/src/agent/schedule.js.map +1 -0
  11. package/dist/src/agent/sessions.d.ts +427 -0
  12. package/dist/src/agent/sessions.d.ts.map +1 -0
  13. package/dist/src/agent/sessions.js +868 -0
  14. package/dist/src/agent/sessions.js.map +1 -0
  15. package/dist/src/agent/sourceConsumption.d.ts +79 -0
  16. package/dist/src/agent/sourceConsumption.d.ts.map +1 -0
  17. package/dist/src/agent/sourceConsumption.js +191 -0
  18. package/dist/src/agent/sourceConsumption.js.map +1 -0
  19. package/dist/src/agent/watch.d.ts +76 -0
  20. package/dist/src/agent/watch.d.ts.map +1 -0
  21. package/dist/src/agent/watch.js +45 -0
  22. package/dist/src/agent/watch.js.map +1 -0
  23. package/dist/src/agent/writePlanning.d.ts +154 -0
  24. package/dist/src/agent/writePlanning.d.ts.map +1 -0
  25. package/dist/src/agent/writePlanning.js +210 -0
  26. package/dist/src/agent/writePlanning.js.map +1 -0
  27. package/dist/src/bin.d.ts +3 -0
  28. package/dist/src/bin.d.ts.map +1 -0
  29. package/dist/src/bin.js +9 -3
  30. package/dist/src/bin.js.map +1 -1
  31. package/dist/src/cli/agentWrite.d.ts +164 -0
  32. package/dist/src/cli/agentWrite.d.ts.map +1 -0
  33. package/dist/src/cli/agentWrite.js +362 -0
  34. package/dist/src/cli/agentWrite.js.map +1 -0
  35. package/dist/src/cli/auth.d.ts +8 -0
  36. package/dist/src/cli/auth.d.ts.map +1 -0
  37. package/dist/src/cli/auth.js +10 -10
  38. package/dist/src/cli/auth.js.map +1 -1
  39. package/dist/src/cli/calendar.d.ts +42 -0
  40. package/dist/src/cli/calendar.d.ts.map +1 -0
  41. package/dist/src/cli/calendar.js +189 -0
  42. package/dist/src/cli/calendar.js.map +1 -0
  43. package/dist/src/cli/config.d.ts +12 -0
  44. package/dist/src/cli/config.d.ts.map +1 -0
  45. package/dist/src/cli/config.js +163 -21
  46. package/dist/src/cli/config.js.map +1 -1
  47. package/dist/src/cli/fetchTicket.d.ts +51 -0
  48. package/dist/src/cli/fetchTicket.d.ts.map +1 -0
  49. package/dist/src/cli/fetchTicket.js +18 -2
  50. package/dist/src/cli/fetchTicket.js.map +1 -1
  51. package/dist/src/cli/fuzzySelect.d.ts +24 -0
  52. package/dist/src/cli/fuzzySelect.d.ts.map +1 -0
  53. package/dist/src/cli/layers.d.ts +40 -0
  54. package/dist/src/cli/layers.d.ts.map +1 -0
  55. package/dist/src/cli/layers.js +56 -12
  56. package/dist/src/cli/layers.js.map +1 -1
  57. package/dist/src/cli/list.d.ts +8 -0
  58. package/dist/src/cli/list.d.ts.map +1 -0
  59. package/dist/src/cli/list.js +2 -2
  60. package/dist/src/cli/list.js.map +1 -1
  61. package/dist/src/cli/reconcile.d.ts +129 -0
  62. package/dist/src/cli/reconcile.d.ts.map +1 -0
  63. package/dist/src/cli/reconcile.js +635 -46
  64. package/dist/src/cli/reconcile.js.map +1 -1
  65. package/dist/src/cli/root.d.ts +15 -0
  66. package/dist/src/cli/root.d.ts.map +1 -0
  67. package/dist/src/cli/root.js +4 -3
  68. package/dist/src/cli/root.js.map +1 -1
  69. package/dist/src/cli/runtimeFailure.d.ts +10 -0
  70. package/dist/src/cli/runtimeFailure.d.ts.map +1 -0
  71. package/dist/src/cli/runtimeFailure.js +17 -0
  72. package/dist/src/cli/runtimeFailure.js.map +1 -0
  73. package/dist/src/cli/setup.d.ts +10 -0
  74. package/dist/src/cli/setup.d.ts.map +1 -0
  75. package/dist/src/cli/setup.js +7 -7
  76. package/dist/src/cli/setup.js.map +1 -1
  77. package/dist/src/cli/timer/discard.d.ts +4 -0
  78. package/dist/src/cli/timer/discard.d.ts.map +1 -0
  79. package/dist/src/cli/timer/discard.js +2 -2
  80. package/dist/src/cli/timer/discard.js.map +1 -1
  81. package/dist/src/cli/timer/edit.d.ts +22 -0
  82. package/dist/src/cli/timer/edit.d.ts.map +1 -0
  83. package/dist/src/cli/timer/edit.js +62 -42
  84. package/dist/src/cli/timer/edit.js.map +1 -1
  85. package/dist/src/cli/timer/index.d.ts +12 -0
  86. package/dist/src/cli/timer/index.d.ts.map +1 -0
  87. package/dist/src/cli/timer/log.d.ts +16 -0
  88. package/dist/src/cli/timer/log.d.ts.map +1 -0
  89. package/dist/src/cli/timer/log.js +6 -6
  90. package/dist/src/cli/timer/log.js.map +1 -1
  91. package/dist/src/cli/timer/start.d.ts +21 -0
  92. package/dist/src/cli/timer/start.d.ts.map +1 -0
  93. package/dist/src/cli/timer/start.js +9 -9
  94. package/dist/src/cli/timer/start.js.map +1 -1
  95. package/dist/src/cli/timer/status.d.ts +22 -0
  96. package/dist/src/cli/timer/status.d.ts.map +1 -0
  97. package/dist/src/cli/timer/status.js +110 -71
  98. package/dist/src/cli/timer/status.js.map +1 -1
  99. package/dist/src/cli/timer/stop.d.ts +48 -0
  100. package/dist/src/cli/timer/stop.d.ts.map +1 -0
  101. package/dist/src/cli/timer/stop.js +19 -19
  102. package/dist/src/cli/timer/stop.js.map +1 -1
  103. package/dist/src/cli/timer.d.ts +11 -0
  104. package/dist/src/cli/timer.d.ts.map +1 -0
  105. package/dist/src/cli/timer.js +1 -1
  106. package/dist/src/cli/timer.js.map +1 -1
  107. package/dist/src/cli/watch.d.ts +54 -0
  108. package/dist/src/cli/watch.d.ts.map +1 -0
  109. package/dist/src/cli/watch.js +412 -0
  110. package/dist/src/cli/watch.js.map +1 -0
  111. package/dist/src/cli/watchLease.d.ts +99 -0
  112. package/dist/src/cli/watchLease.d.ts.map +1 -0
  113. package/dist/src/cli/watchLease.js +204 -0
  114. package/dist/src/cli/watchLease.js.map +1 -0
  115. package/dist/src/cli/writerGuard.d.ts +37 -0
  116. package/dist/src/cli/writerGuard.d.ts.map +1 -0
  117. package/dist/src/cli/writerGuard.js +92 -0
  118. package/dist/src/cli/writerGuard.js.map +1 -0
  119. package/dist/src/index.d.ts +46 -0
  120. package/dist/src/index.d.ts.map +1 -0
  121. package/dist/src/index.js +46 -0
  122. package/dist/src/index.js.map +1 -0
  123. package/dist/src/main.d.ts +4 -0
  124. package/dist/src/main.d.ts.map +1 -0
  125. package/dist/src/services/AgentSessionReader.d.ts +121 -0
  126. package/dist/src/services/AgentSessionReader.d.ts.map +1 -0
  127. package/dist/src/services/AgentSessionReader.js +392 -0
  128. package/dist/src/services/AgentSessionReader.js.map +1 -0
  129. package/dist/src/services/ClockifyAuth.d.ts +47 -0
  130. package/dist/src/services/ClockifyAuth.d.ts.map +1 -0
  131. package/dist/src/services/ClockifyAuth.js +2 -2
  132. package/dist/src/services/ClockifyAuth.js.map +1 -1
  133. package/dist/src/services/CodexTranscript.d.ts +112 -0
  134. package/dist/src/services/CodexTranscript.d.ts.map +1 -0
  135. package/dist/src/services/CodexTranscript.js +96 -0
  136. package/dist/src/services/CodexTranscript.js.map +1 -0
  137. package/dist/src/services/ConfigService.d.ts +99 -0
  138. package/dist/src/services/ConfigService.d.ts.map +1 -0
  139. package/dist/src/services/ConfigService.js +79 -7
  140. package/dist/src/services/ConfigService.js.map +1 -1
  141. package/dist/src/services/HomeDirectory.d.ts +17 -0
  142. package/dist/src/services/HomeDirectory.d.ts.map +1 -0
  143. package/dist/src/services/HomeDirectory.js +1 -1
  144. package/dist/src/services/IssueFacts.d.ts +127 -0
  145. package/dist/src/services/IssueFacts.d.ts.map +1 -0
  146. package/dist/src/services/IssueFacts.js +277 -0
  147. package/dist/src/services/IssueFacts.js.map +1 -0
  148. package/dist/src/services/ProviderDeletion.d.ts +19 -0
  149. package/dist/src/services/ProviderDeletion.d.ts.map +1 -0
  150. package/dist/src/services/ProviderDeletion.js +37 -0
  151. package/dist/src/services/ProviderDeletion.js.map +1 -0
  152. package/dist/src/services/ReconcileService.d.ts +378 -0
  153. package/dist/src/services/ReconcileService.d.ts.map +1 -0
  154. package/dist/src/services/ReconcileService.js +1270 -79
  155. package/dist/src/services/ReconcileService.js.map +1 -1
  156. package/dist/src/services/SavedEntries.d.ts +40 -0
  157. package/dist/src/services/SavedEntries.d.ts.map +1 -0
  158. package/dist/src/services/SavedEntries.js +209 -0
  159. package/dist/src/services/SavedEntries.js.map +1 -0
  160. package/dist/src/services/SessionAttributor.d.ts +114 -0
  161. package/dist/src/services/SessionAttributor.d.ts.map +1 -0
  162. package/dist/src/services/SessionAttributor.js +240 -0
  163. package/dist/src/services/SessionAttributor.js.map +1 -0
  164. package/dist/src/services/SourceLedger.d.ts +104 -0
  165. package/dist/src/services/SourceLedger.d.ts.map +1 -0
  166. package/dist/src/services/SourceLedger.js +302 -0
  167. package/dist/src/services/SourceLedger.js.map +1 -0
  168. package/dist/src/services/StateWriter.d.ts +39 -0
  169. package/dist/src/services/StateWriter.d.ts.map +1 -0
  170. package/dist/src/services/TicketService.d.ts +63 -0
  171. package/dist/src/services/TicketService.d.ts.map +1 -0
  172. package/dist/src/services/TimerService.d.ts +145 -0
  173. package/dist/src/services/TimerService.d.ts.map +1 -0
  174. package/dist/src/services/TimerService.js +113 -80
  175. package/dist/src/services/TimerService.js.map +1 -1
  176. package/dist/src/services/internal/JiraWorklogPost.d.ts +7 -0
  177. package/dist/src/services/internal/JiraWorklogPost.d.ts.map +1 -0
  178. package/dist/src/services/internal/JiraWorklogPost.js +32 -0
  179. package/dist/src/services/internal/JiraWorklogPost.js.map +1 -0
  180. package/dist/src/testing/fakeHeadless.d.ts +318 -0
  181. package/dist/src/testing/fakeHeadless.d.ts.map +1 -0
  182. package/dist/src/testing/fakeHeadless.js +1149 -0
  183. package/dist/src/testing/fakeHeadless.js.map +1 -0
  184. package/dist/src/tui/App.d.ts +6 -0
  185. package/dist/src/tui/App.d.ts.map +1 -0
  186. package/dist/src/tui/App.js +1 -1
  187. package/dist/src/tui/App.js.map +1 -1
  188. package/dist/src/tui/atoms/runtime.d.ts +8 -0
  189. package/dist/src/tui/atoms/runtime.d.ts.map +1 -0
  190. package/dist/src/tui/atoms/runtime.js +1 -1
  191. package/dist/src/tui/atoms/runtime.js.map +1 -1
  192. package/dist/src/tui/atoms/tickets.d.ts +3 -0
  193. package/dist/src/tui/atoms/tickets.d.ts.map +1 -0
  194. package/dist/src/tui/atoms/timer.d.ts +11 -0
  195. package/dist/src/tui/atoms/timer.d.ts.map +1 -0
  196. package/dist/src/tui/atoms/timer.js +1 -1
  197. package/dist/src/tui/atoms/timer.js.map +1 -1
  198. package/dist/src/tui/atoms/ui.d.ts +11 -0
  199. package/dist/src/tui/atoms/ui.d.ts.map +1 -0
  200. package/dist/src/tui/atoms/ui.js +1 -1
  201. package/dist/src/tui/atoms/ui.js.map +1 -1
  202. package/dist/src/tui/components/BigTimer.d.ts +2 -0
  203. package/dist/src/tui/components/BigTimer.d.ts.map +1 -0
  204. package/dist/src/tui/components/Footer.d.ts +2 -0
  205. package/dist/src/tui/components/Footer.d.ts.map +1 -0
  206. package/dist/src/tui/components/Header.d.ts +2 -0
  207. package/dist/src/tui/components/Header.d.ts.map +1 -0
  208. package/dist/src/tui/components/Header.js +1 -1
  209. package/dist/src/tui/components/Header.js.map +1 -1
  210. package/dist/src/tui/components/PopupInput.d.ts +18 -0
  211. package/dist/src/tui/components/PopupInput.d.ts.map +1 -0
  212. package/dist/src/tui/components/PopupMessage.d.ts +20 -0
  213. package/dist/src/tui/components/PopupMessage.d.ts.map +1 -0
  214. package/dist/src/tui/components/TicketList.d.ts +2 -0
  215. package/dist/src/tui/components/TicketList.d.ts.map +1 -0
  216. package/dist/src/tui/components/TicketList.js +1 -1
  217. package/dist/src/tui/components/TicketList.js.map +1 -1
  218. package/dist/src/tui/components/TicketRow.d.ts +8 -0
  219. package/dist/src/tui/components/TicketRow.d.ts.map +1 -0
  220. package/dist/src/tui/components/TimerDisplay.d.ts +2 -0
  221. package/dist/src/tui/components/TimerDisplay.d.ts.map +1 -0
  222. package/dist/src/tui/components/index.d.ts +12 -0
  223. package/dist/src/tui/components/index.d.ts.map +1 -0
  224. package/dist/src/tui/context/theme.d.ts +15 -0
  225. package/dist/src/tui/context/theme.d.ts.map +1 -0
  226. package/dist/src/tui/hooks/useElapsedTimer.d.ts +6 -0
  227. package/dist/src/tui/hooks/useElapsedTimer.d.ts.map +1 -0
  228. package/dist/src/tui/hooks/useElapsedTimer.js +1 -1
  229. package/dist/src/tui/hooks/useElapsedTimer.js.map +1 -1
  230. package/dist/src/tui/hooks/useTerminalSize.d.ts +5 -0
  231. package/dist/src/tui/hooks/useTerminalSize.d.ts.map +1 -0
  232. package/dist/src/utils/hints.d.ts +12 -0
  233. package/dist/src/utils/hints.d.ts.map +1 -0
  234. package/dist/src/utils/hints.js +12 -0
  235. package/dist/src/utils/hints.js.map +1 -0
  236. package/dist/src/utils/time.d.ts +104 -0
  237. package/dist/src/utils/time.d.ts.map +1 -0
  238. package/dist/src/utils/time.js +74 -8
  239. package/dist/src/utils/time.js.map +1 -1
  240. package/dist/tsconfig.tsbuildinfo +1 -1
  241. package/nvim/lua/jcf/state.lua +191 -13
  242. package/package.json +36 -18
  243. package/skills/jcf/SKILL.md +93 -1
@@ -0,0 +1,302 @@
1
+ /** Private, versioned bindings between confirmed session writes and provider entries. */
2
+ import * as Context from "effect/Context";
3
+ import * as Effect from "effect/Effect";
4
+ import * as FileSystem from "effect/FileSystem";
5
+ import * as Layer from "effect/Layer";
6
+ import * as Option from "effect/Option";
7
+ import * as Path from "effect/Path";
8
+ import * as Schema from "effect/Schema";
9
+ import { ConfigService } from "./ConfigService.js";
10
+ const validDuration = (value) => value.endMs > value.startMs && Math.abs((value.endMs - value.startMs) / 1000 - value.seconds) < 0.000_001;
11
+ const Identity = Schema.Struct({
12
+ provider: Schema.Literals(["clockify", "jira"]),
13
+ scope: Schema.NonEmptyString,
14
+ rowId: Schema.NonEmptyString,
15
+ sourceStartMs: Schema.Finite,
16
+ startMs: Schema.Finite,
17
+ endMs: Schema.Finite,
18
+ seconds: Schema.Finite.check(Schema.isGreaterThan(0)),
19
+ ticketKey: Schema.NonEmptyString
20
+ }).check(Schema.makeFilter(validDuration, {
21
+ expected: "source segment duration matches its interval"
22
+ }));
23
+ const LegacyBinding = Identity.pipe(Schema.fieldsAssign({ entryId: Schema.NonEmptyString }));
24
+ /** Jira provider time, not the machine clock; old bindings have no ordering checkpoint. */
25
+ const jiraCreatedAtMs = Schema.Number.check(Schema.makeFilter((value) => Number.isSafeInteger(value) && value >= 0, { expected: "safe Jira worklog creation timestamp" }));
26
+ const Binding = LegacyBinding.pipe(Schema.fieldsAssign({
27
+ jiraCreatedAtMs: Schema.optionalKey(jiraCreatedAtMs)
28
+ }));
29
+ const ReviewedWindow = Schema.Struct({
30
+ provider: Schema.Literals(["clockify", "jira"]),
31
+ scope: Schema.NonEmptyString,
32
+ fromMs: Schema.Finite,
33
+ toMs: Schema.Finite
34
+ }).check(Schema.makeFilter((value) => value.toMs > value.fromMs, { expected: "non-empty review window" }));
35
+ const ObservedUnbound = Schema.Struct({
36
+ provider: Schema.Literals(["clockify", "jira"]),
37
+ scope: Schema.NonEmptyString,
38
+ entryId: Schema.NonEmptyString,
39
+ startMs: Schema.Finite
40
+ });
41
+ const LegacyLedgerFile = Schema.Struct({
42
+ version: Schema.Literal(1),
43
+ reviewedWindows: Schema.Array(ReviewedWindow),
44
+ pending: Schema.Array(Identity),
45
+ bindings: Schema.Array(LegacyBinding)
46
+ });
47
+ const V2LedgerFile = Schema.Struct({
48
+ version: Schema.Literal(2),
49
+ reviewedWindows: Schema.Array(ReviewedWindow),
50
+ pending: Schema.Array(Identity),
51
+ bindings: Schema.Array(LegacyBinding),
52
+ observedUnbound: Schema.Array(ObservedUnbound)
53
+ });
54
+ const V3LedgerFile = Schema.Struct({
55
+ version: Schema.Literal(3),
56
+ reviewedWindows: Schema.Array(ReviewedWindow),
57
+ pending: Schema.Array(Identity),
58
+ bindings: Schema.Array(LegacyBinding),
59
+ observedUnbound: Schema.Array(ObservedUnbound)
60
+ });
61
+ const LedgerFile = Schema.Struct({
62
+ version: Schema.Literal(4),
63
+ reviewedWindows: Schema.Array(ReviewedWindow),
64
+ pending: Schema.Array(Identity),
65
+ bindings: Schema.Array(Binding),
66
+ observedUnbound: Schema.Array(ObservedUnbound)
67
+ }).check(Schema.makeFilter((value) => {
68
+ const keys = value.bindings.map((binding) => JSON.stringify([binding.provider, binding.scope, binding.entryId]));
69
+ const observedKeys = value.observedUnbound.map((entry) => JSON.stringify([entry.provider, entry.scope, entry.entryId]));
70
+ return new Set(keys).size === keys.length &&
71
+ new Set(observedKeys).size === observedKeys.length &&
72
+ observedKeys.every((key) => !keys.includes(key)) &&
73
+ value.observedUnbound.every((entry) => entry.entryId.trim() !== "" &&
74
+ value.reviewedWindows.some((window) => window.provider === entry.provider && window.scope === entry.scope &&
75
+ window.fromMs <= entry.startMs && entry.startMs < window.toMs)) &&
76
+ value.pending.every(validDuration) && value.bindings.every((binding) => validDuration(binding) && (binding.jiraCreatedAtMs === undefined || binding.provider === "jira"));
77
+ }, { expected: "valid reviewed observations, unique provider entries and source durations" }));
78
+ const empty = { version: 4, reviewedWindows: [], pending: [], bindings: [], observedUnbound: [] };
79
+ const decodeStored = Schema.decodeUnknownEffect(Schema.fromJsonString(Schema.Union([LegacyLedgerFile, V2LedgerFile, V3LedgerFile, LedgerFile])), { onExcessProperty: "error" });
80
+ const decode = (content) => decodeStored(content).pipe(Effect.flatMap((stored) => stored.version === 4
81
+ ? Effect.succeed(stored)
82
+ : Schema.decodeEffect(LedgerFile)({
83
+ ...stored,
84
+ version: 4,
85
+ observedUnbound: stored.version === 1 ? [] : stored.observedUnbound
86
+ })));
87
+ const positiveProcessNumber = Schema.Number.check(Schema.makeFilter((value) => Number.isSafeInteger(value) && value > 0, { expected: "positive process identity" }));
88
+ const LockOwner = Schema.Struct({
89
+ version: Schema.Literal(1),
90
+ pid: positiveProcessNumber,
91
+ namespace: positiveProcessNumber
92
+ });
93
+ const decodeLockOwner = Schema.decodeUnknownEffect(Schema.fromJsonString(LockOwner), { onExcessProperty: "error" });
94
+ const lockOwner = (pid, namespace) => ({ version: 1, pid, namespace });
95
+ export class SourceLedgerError extends Schema.TaggedError()("SourceLedgerError", {
96
+ message: Schema.String,
97
+ cause: Schema.optionalKey(Schema.Defect())
98
+ }) {
99
+ }
100
+ export class SourceLedger extends Context.Service()("jcf/SourceLedger") {
101
+ }
102
+ const sameIdentity = (left, right) => left.provider === right.provider && left.scope === right.scope && left.rowId === right.rowId &&
103
+ left.sourceStartMs === right.sourceStartMs && left.startMs === right.startMs &&
104
+ left.endMs === right.endMs && left.seconds === right.seconds && left.ticketKey === right.ticketKey;
105
+ const hasLegacyClockify = (current, legacyScope) => current.reviewedWindows.some((value) => value.provider === "clockify" && value.scope === legacyScope) ||
106
+ current.observedUnbound.some((value) => value.provider === "clockify" && value.scope === legacyScope) ||
107
+ current.pending.some((value) => value.provider === "clockify" && value.scope === legacyScope) ||
108
+ current.bindings.some((value) => value.provider === "clockify" && value.scope === legacyScope);
109
+ const rejectLegacyClockify = (current, legacyScope) => hasLegacyClockify(current, legacyScope)
110
+ ? Effect.fail(new SourceLedgerError({ message: "Earlier Clockify scope needs private manual consumption review" }))
111
+ : Effect.void;
112
+ /** A pending remote create never becomes permission to repeat it after a crash. */
113
+ export const layer = Layer.effect(SourceLedger, Effect.gen(function* () {
114
+ const fs = yield* FileSystem.FileSystem;
115
+ const path = yield* Path.Path;
116
+ const config = yield* ConfigService;
117
+ const dir = yield* config.configDir;
118
+ const file = path.join(dir, "source-consumption.v1.json");
119
+ const temporary = `${file}.tmp`;
120
+ const lock = `${file}.lock`;
121
+ const recovery = `${lock}.recovery`;
122
+ const ownLockIdentity = Effect.gen(function* () {
123
+ const stat = yield* fs.readFileString("/proc/self/stat");
124
+ const pid = Number(/^\d+/u.exec(stat)?.[0]);
125
+ const namespace = Option.getOrUndefined((yield* fs.stat("/proc/self/ns/pid")).ino);
126
+ if (!Number.isSafeInteger(pid) || pid <= 0 || namespace === undefined ||
127
+ !Number.isSafeInteger(namespace) || namespace <= 0)
128
+ return null;
129
+ return lockOwner(pid, namespace);
130
+ }).pipe(Effect.catch(() => Effect.succeed(null)));
131
+ const acquireLock = Effect.gen(function* () {
132
+ // On hosts without a verifiable process namespace, exclusive creation still works; a
133
+ // leftover lock requires manual recovery rather than a guessed liveness decision.
134
+ const owner = yield* ownLockIdentity;
135
+ const content = owner === null ? "held" : JSON.stringify(owner);
136
+ yield* fs.writeFileString(lock, content, { flag: "wx", mode: 0o600 }).pipe(Effect.catch((cause) => Effect.gen(function* () {
137
+ if (!(yield* fs.exists(lock)))
138
+ return yield* cause;
139
+ yield* fs.writeFileString(recovery, "recovering", { flag: "wx", mode: 0o600 });
140
+ return yield* Effect.gen(function* () {
141
+ const info = yield* fs.stat(lock);
142
+ const realDirectory = yield* fs.realPath(dir);
143
+ if (info.type !== "File" || (info.mode & 0o077) !== 0 ||
144
+ (yield* fs.realPath(lock)) !== path.join(realDirectory, "source-consumption.v1.json.lock")) {
145
+ return yield* new SourceLedgerError({
146
+ message: "Private consumption lock has unsafe type or permissions"
147
+ });
148
+ }
149
+ const previous = yield* decodeLockOwner(yield* fs.readFileString(lock)).pipe(Effect.mapError((decodeCause) => new SourceLedgerError({
150
+ message: "Private consumption lock needs manual recovery",
151
+ cause: decodeCause
152
+ })));
153
+ if (owner === null || owner.namespace !== previous.namespace || owner.pid === previous.pid) {
154
+ return yield* new SourceLedgerError({ message: "Private consumption lock may have a live holder" });
155
+ }
156
+ const holderGone = yield* fs.stat(`/proc/${previous.pid}/stat`).pipe(Effect.map(() => false), Effect.catch((probeCause) => probeCause.reason._tag === "NotFound"
157
+ ? Effect.succeed(true)
158
+ : Effect.fail(probeCause)));
159
+ if (!holderGone) {
160
+ return yield* new SourceLedgerError({ message: "Private consumption lock may have a live holder" });
161
+ }
162
+ yield* fs.remove(lock);
163
+ yield* fs.writeFileString(lock, content, { flag: "wx", mode: 0o600 });
164
+ }).pipe(Effect.onExit(() => fs.remove(recovery)));
165
+ })));
166
+ });
167
+ const syncPath = (target) => Effect.scoped(Effect.gen(function* () {
168
+ const handle = yield* fs.open(target, { flag: "r" });
169
+ yield* handle.sync;
170
+ }));
171
+ const read = Effect.gen(function* () {
172
+ const exists = yield* fs.exists(file);
173
+ if (!exists)
174
+ return empty;
175
+ const info = yield* fs.stat(file);
176
+ const directory = yield* fs.stat(dir);
177
+ const realDirectory = yield* fs.realPath(dir);
178
+ const realFile = yield* fs.realPath(file);
179
+ if (info.type !== "File" || (info.mode & 0o077) !== 0 ||
180
+ directory.type !== "Directory" || (directory.mode & 0o022) !== 0 ||
181
+ realFile !== path.join(realDirectory, "source-consumption.v1.json")) {
182
+ return yield* new SourceLedgerError({ message: "Private consumption ledger has unsafe permissions or type" });
183
+ }
184
+ return yield* decode(yield* fs.readFileString(file)).pipe(Effect.mapError((cause) => new SourceLedgerError({ message: "Private consumption ledger is invalid", cause })));
185
+ }).pipe(Effect.mapError((cause) => cause._tag === "SourceLedgerError"
186
+ ? cause
187
+ : new SourceLedgerError({ message: "Could not read private consumption ledger", cause })));
188
+ const update = (change) => Effect.gen(function* () {
189
+ yield* fs.makeDirectory(dir, { recursive: true });
190
+ const directory = yield* fs.stat(dir);
191
+ if (directory.type !== "Directory" || (directory.mode & 0o022) !== 0) {
192
+ return yield* new SourceLedgerError({ message: "Private consumption directory is writable by others" });
193
+ }
194
+ yield* acquireLock;
195
+ return yield* Effect.gen(function* () {
196
+ const next = yield* change(yield* read);
197
+ yield* Schema.decodeEffect(LedgerFile)(next).pipe(Effect.mapError((cause) => new SourceLedgerError({ message: "Invalid consumption ledger update", cause })));
198
+ // Exclusive creation makes a leftover temp file a visible recovery case, not an overwrite.
199
+ yield* fs.writeFileString(temporary, JSON.stringify(next), { flag: "wx", mode: 0o600 });
200
+ yield* syncPath(temporary);
201
+ yield* fs.rename(temporary, file);
202
+ yield* syncPath(dir);
203
+ }).pipe(Effect.onExit(() => fs.remove(lock)));
204
+ }).pipe(Effect.mapError((cause) => cause._tag === "SourceLedgerError"
205
+ ? cause
206
+ : new SourceLedgerError({ message: "Could not update private consumption ledger", cause })));
207
+ const assertNoLegacyClockify = (legacyScope) => read.pipe(Effect.flatMap((current) => rejectLegacyClockify(current, legacyScope)));
208
+ const reserve = (identity, legacyScope) => update((current) => Effect.gen(function* () {
209
+ if (identity.provider === "clockify" && legacyScope !== undefined) {
210
+ yield* rejectLegacyClockify(current, legacyScope);
211
+ }
212
+ yield* Schema.decodeEffect(Identity)(identity).pipe(Effect.mapError((cause) => new SourceLedgerError({ message: "Invalid source identity", cause })));
213
+ if (identity.endMs <= identity.startMs || identity.seconds <= 0) {
214
+ return yield* new SourceLedgerError({ message: "Invalid source duration" });
215
+ }
216
+ if (!current.reviewedWindows.some((window) => window.provider === identity.provider &&
217
+ window.scope === identity.scope && window.fromMs <= identity.startMs && window.toMs >= identity.endMs)) {
218
+ return yield* new SourceLedgerError({ message: "Earlier provider entries need manual consumption review" });
219
+ }
220
+ if (current.pending.some((pending) => pending.provider === identity.provider &&
221
+ pending.scope === identity.scope && pending.rowId === identity.rowId)) {
222
+ return yield* new SourceLedgerError({
223
+ message: "Source has an unresolved remote write; reconcile it manually"
224
+ });
225
+ }
226
+ return { ...current, pending: [...current.pending, identity] };
227
+ }));
228
+ const bind = (identity, entryId, createdAtMs) => update((current) => Effect.gen(function* () {
229
+ const pending = current.pending.find((value) => sameIdentity(value, identity));
230
+ if (pending === undefined || entryId.trim() === "" ||
231
+ createdAtMs !== undefined &&
232
+ (identity.provider !== "jira" || !Number.isSafeInteger(createdAtMs) || createdAtMs < 0)) {
233
+ return yield* new SourceLedgerError({
234
+ message: "Successful write has no unique pending identity or provider ID"
235
+ });
236
+ }
237
+ if (current.bindings.some((value) => value.provider === identity.provider &&
238
+ value.scope === identity.scope && value.entryId === entryId)) {
239
+ return yield* new SourceLedgerError({ message: "Provider entry is already bound" });
240
+ }
241
+ const binding = createdAtMs === undefined
242
+ ? { ...pending, entryId }
243
+ : { ...pending, entryId, jiraCreatedAtMs: createdAtMs };
244
+ return {
245
+ ...current,
246
+ pending: current.pending.filter((value) => !sameIdentity(value, identity)),
247
+ bindings: [...current.bindings, binding]
248
+ };
249
+ }));
250
+ const release = (identity) => update((current) => Effect.succeed({
251
+ ...current,
252
+ pending: current.pending.filter((value) => !sameIdentity(value, identity))
253
+ }));
254
+ const ensureWindow = (window, observed, markerBindings, legacyScope) => update((current) => Effect.gen(function* () {
255
+ if (window.provider === "clockify" && legacyScope !== undefined) {
256
+ yield* rejectLegacyClockify(current, legacyScope);
257
+ }
258
+ if (window.toMs <= window.fromMs ||
259
+ observed.some((entry) => entry.entryId.trim() === "" || !Number.isFinite(entry.startMs))) {
260
+ return yield* new SourceLedgerError({ message: "Invalid provider review window" });
261
+ }
262
+ const priorWindows = current.reviewedWindows.filter((known) => known.provider === window.provider && known.scope === window.scope);
263
+ const latestReviewedEnd = priorWindows.reduce((latest, known) => Math.max(latest, known.toMs), -Infinity);
264
+ const knownBindings = [...current.bindings, ...markerBindings].filter((binding) => binding.provider === window.provider && binding.scope === window.scope);
265
+ const knownBoundIds = new Set(knownBindings.map((binding) => binding.entryId));
266
+ const previousOrdinary = current.observedUnbound.filter((entry) => entry.provider === window.provider && entry.scope === window.scope);
267
+ const ordinaryById = new Map(previousOrdinary.map((entry) => [entry.entryId, entry.startMs]));
268
+ if (new Set(observed.map((entry) => entry.entryId)).size !== observed.length ||
269
+ markerBindings.some((binding) => binding.provider !== window.provider || binding.scope !== window.scope ||
270
+ binding.entryId.trim() === "" ||
271
+ ordinaryById.has(binding.entryId)) ||
272
+ observed.some((entry) => ordinaryById.has(entry.entryId) && ordinaryById.get(entry.entryId) !== entry.startMs)) {
273
+ return yield* new SourceLedgerError({
274
+ message: "Unlinked earlier provider entries need private manual review before session writes"
275
+ });
276
+ }
277
+ const newlyOrdinary = observed.filter((entry) => !knownBoundIds.has(entry.entryId) && !ordinaryById.has(entry.entryId));
278
+ if (newlyOrdinary.some((entry) => priorWindows.length === 0 || window.fromMs > latestReviewedEnd ||
279
+ entry.startMs < latestReviewedEnd ||
280
+ entry.startMs < window.fromMs || entry.startMs >= window.toMs)) {
281
+ return yield* new SourceLedgerError({
282
+ message: "Unlinked earlier provider entries need private manual review before session writes"
283
+ });
284
+ }
285
+ const covered = priorWindows.some((known) => known.fromMs <= window.fromMs && known.toMs >= window.toMs);
286
+ return {
287
+ ...current,
288
+ reviewedWindows: covered ? current.reviewedWindows : [...current.reviewedWindows, window],
289
+ bindings: [
290
+ ...current.bindings,
291
+ ...markerBindings.filter((binding) => !current.bindings.some((known) => known.provider === binding.provider &&
292
+ known.scope === binding.scope && known.entryId === binding.entryId))
293
+ ],
294
+ observedUnbound: [
295
+ ...current.observedUnbound,
296
+ ...newlyOrdinary.map((entry) => ({ provider: window.provider, scope: window.scope, ...entry }))
297
+ ]
298
+ };
299
+ }));
300
+ return SourceLedger.of({ read, assertNoLegacyClockify, reserve, bind, release, ensureWindow });
301
+ }));
302
+ //# sourceMappingURL=SourceLedger.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"SourceLedger.js","sourceRoot":"","sources":["../../../src/services/SourceLedger.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,39 @@
1
+ /**
2
+ * Atomic timer state persistence to `~/.jcf/state.json`.
3
+ *
4
+ * **Mental model**
5
+ *
6
+ * - **Atomic writes**: Write goes to a `.tmp` file then `rename` — prevents corruption if
7
+ * the process crashes mid-write.
8
+ * - **External consumption**: The state file is read by the Neovim plugin and statusline
9
+ * integrations to show timer state outside the TUI.
10
+ *
11
+ * @module
12
+ */
13
+ import * as Context from "effect/Context";
14
+ import * as Effect from "effect/Effect";
15
+ import * as FileSystem from "effect/FileSystem";
16
+ import * as Layer from "effect/Layer";
17
+ import * as Path from "effect/Path";
18
+ import { HomeDirectory } from "./HomeDirectory.js";
19
+ export interface TimerStateFile {
20
+ readonly active: boolean;
21
+ readonly ticketKey: string | null;
22
+ readonly summary: string | null;
23
+ readonly project: string | null;
24
+ readonly startedAt: string | null;
25
+ readonly startedAt_unix: number | null;
26
+ readonly elapsed: number;
27
+ readonly clockifyEntryId: string | null;
28
+ }
29
+ export interface StateWriterContract {
30
+ readonly write: (state: TimerStateFile) => Effect.Effect<void>;
31
+ readonly read: Effect.Effect<TimerStateFile>;
32
+ readonly clear: Effect.Effect<void>;
33
+ }
34
+ declare const StateWriter_base: Context.ServiceClass<StateWriter, "jcf/StateWriter", StateWriterContract>;
35
+ export declare class StateWriter extends StateWriter_base {
36
+ }
37
+ export declare const layer: Layer.Layer<StateWriter, never, FileSystem.FileSystem | HomeDirectory | Path.Path>;
38
+ export {};
39
+ //# sourceMappingURL=StateWriter.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"StateWriter.d.ts","sourceRoot":"","sources":["../../../src/services/StateWriter.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;GAWG;AACH,OAAO,KAAK,OAAO,MAAM,gBAAgB,CAAA;AACzC,OAAO,KAAK,MAAM,MAAM,eAAe,CAAA;AACvC,OAAO,KAAK,UAAU,MAAM,mBAAmB,CAAA;AAC/C,OAAO,KAAK,KAAK,MAAM,cAAc,CAAA;AACrC,OAAO,KAAK,IAAI,MAAM,aAAa,CAAA;AAEnC,OAAO,EAAE,aAAa,EAAE,MAAM,oBAAoB,CAAA;AAElD,MAAM,WAAW,cAAc;IAC7B,QAAQ,CAAC,MAAM,EAAE,OAAO,CAAA;IACxB,QAAQ,CAAC,SAAS,EAAE,MAAM,GAAG,IAAI,CAAA;IACjC,QAAQ,CAAC,OAAO,EAAE,MAAM,GAAG,IAAI,CAAA;IAC/B,QAAQ,CAAC,OAAO,EAAE,MAAM,GAAG,IAAI,CAAA;IAC/B,QAAQ,CAAC,SAAS,EAAE,MAAM,GAAG,IAAI,CAAA;IACjC,QAAQ,CAAC,cAAc,EAAE,MAAM,GAAG,IAAI,CAAA;IACtC,QAAQ,CAAC,OAAO,EAAE,MAAM,CAAA;IACxB,QAAQ,CAAC,eAAe,EAAE,MAAM,GAAG,IAAI,CAAA;CACxC;AAaD,MAAM,WAAW,mBAAmB;IAClC,QAAQ,CAAC,KAAK,EAAE,CAAC,KAAK,EAAE,cAAc,KAAK,MAAM,CAAC,MAAM,CAAC,IAAI,CAAC,CAAA;IAC9D,QAAQ,CAAC,IAAI,EAAE,MAAM,CAAC,MAAM,CAAC,cAAc,CAAC,CAAA;IAC5C,QAAQ,CAAC,KAAK,EAAE,MAAM,CAAC,MAAM,CAAC,IAAI,CAAC,CAAA;CACpC;;AAED,qBAAa,WAAY,SAAQ,gBAAsE;CAAG;AA4B1G,eAAO,MAAM,KAAK,oFAyCjB,CAAA"}
@@ -0,0 +1,63 @@
1
+ /**
2
+ * Jira ticket fetching with reactive state via SubscriptionRef.
3
+ *
4
+ * **Mental model**
5
+ *
6
+ * - **SubscriptionRef-backed state**: {@link TicketServiceContract.state} is a `SubscriptionRef<TicketState>`
7
+ * that the TUI subscribes to for live updates. {@link TicketServiceContract.refresh} fetches
8
+ * tickets from Jira and updates the ref.
9
+ * - **Field extraction helpers**: `extractNested` and `extractString` safely navigate the
10
+ * loosely-typed Jira API response without runtime crashes.
11
+ * - **In-memory search**: {@link TicketServiceContract.search} filters the cached ticket list
12
+ * by key or summary substring.
13
+ *
14
+ * @module
15
+ */
16
+ import { JiraApiClient } from "@knpkv/jira-api-client";
17
+ import * as Context from "effect/Context";
18
+ import * as Effect from "effect/Effect";
19
+ import * as Layer from "effect/Layer";
20
+ import * as Schema from "effect/Schema";
21
+ import * as SubscriptionRef from "effect/SubscriptionRef";
22
+ import { ConfigService } from "./ConfigService.js";
23
+ export interface JiraTicket {
24
+ readonly key: string;
25
+ readonly summary: string;
26
+ readonly status: string;
27
+ readonly priority: string | null;
28
+ readonly assignee: string | null;
29
+ readonly type: string;
30
+ readonly labels: ReadonlyArray<string>;
31
+ readonly updated: string;
32
+ }
33
+ export interface TicketState {
34
+ readonly tickets: ReadonlyArray<JiraTicket>;
35
+ readonly loading: boolean;
36
+ readonly error: string | null;
37
+ readonly lastRefreshed: Date | null;
38
+ }
39
+ declare const TicketError_base: new <A extends Record<string, any> = {}>(args: import("effect/Types").VoidIfEmpty<{ readonly [P in keyof A as P extends "_tag" ? never : P]: A[P]; }>) => import("effect/Cause").YieldableError & {
40
+ readonly _tag: "TicketError";
41
+ } & Readonly<A>;
42
+ export declare class TicketError extends TicketError_base<{
43
+ readonly message: string;
44
+ readonly cause?: unknown;
45
+ }> {
46
+ }
47
+ /**
48
+ * Shape a raw Jira issue (from `/rest/api/3/issue` or `/search/jql`) into a
49
+ * {@link JiraTicket}. Single source of truth for the nested-field extraction —
50
+ * reused by {@link fetchTicketByKey} so the two never drift.
51
+ */
52
+ export declare const mapIssueToTicket: (issue: Record<string, Schema.Json>, fallbackKey?: string) => JiraTicket;
53
+ export interface TicketServiceContract {
54
+ readonly state: SubscriptionRef.SubscriptionRef<TicketState>;
55
+ readonly refresh: Effect.Effect<void, TicketError>;
56
+ readonly search: (text: string) => Effect.Effect<ReadonlyArray<JiraTicket>>;
57
+ }
58
+ declare const TicketService_base: Context.ServiceClass<TicketService, "jcf/TicketService", TicketServiceContract>;
59
+ export declare class TicketService extends TicketService_base {
60
+ }
61
+ export declare const layer: Layer.Layer<TicketService, never, ConfigService | JiraApiClient>;
62
+ export {};
63
+ //# sourceMappingURL=TicketService.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"TicketService.d.ts","sourceRoot":"","sources":["../../../src/services/TicketService.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;GAcG;AACH,OAAO,EAAE,aAAa,EAAE,MAAM,wBAAwB,CAAA;AACtD,OAAO,KAAK,OAAO,MAAM,gBAAgB,CAAA;AAGzC,OAAO,KAAK,MAAM,MAAM,eAAe,CAAA;AACvC,OAAO,KAAK,KAAK,MAAM,cAAc,CAAA;AAErC,OAAO,KAAK,MAAM,MAAM,eAAe,CAAA;AACvC,OAAO,KAAK,eAAe,MAAM,wBAAwB,CAAA;AACzD,OAAO,EAAE,aAAa,EAAE,MAAM,oBAAoB,CAAA;AAMlD,MAAM,WAAW,UAAU;IACzB,QAAQ,CAAC,GAAG,EAAE,MAAM,CAAA;IACpB,QAAQ,CAAC,OAAO,EAAE,MAAM,CAAA;IACxB,QAAQ,CAAC,MAAM,EAAE,MAAM,CAAA;IACvB,QAAQ,CAAC,QAAQ,EAAE,MAAM,GAAG,IAAI,CAAA;IAChC,QAAQ,CAAC,QAAQ,EAAE,MAAM,GAAG,IAAI,CAAA;IAChC,QAAQ,CAAC,IAAI,EAAE,MAAM,CAAA;IACrB,QAAQ,CAAC,MAAM,EAAE,aAAa,CAAC,MAAM,CAAC,CAAA;IACtC,QAAQ,CAAC,OAAO,EAAE,MAAM,CAAA;CACzB;AAED,MAAM,WAAW,WAAW;IAC1B,QAAQ,CAAC,OAAO,EAAE,aAAa,CAAC,UAAU,CAAC,CAAA;IAC3C,QAAQ,CAAC,OAAO,EAAE,OAAO,CAAA;IACzB,QAAQ,CAAC,KAAK,EAAE,MAAM,GAAG,IAAI,CAAA;IAC7B,QAAQ,CAAC,aAAa,EAAE,IAAI,GAAG,IAAI,CAAA;CACpC;;;;AAED,qBAAa,WAAY,SAAQ,iBAAgC;IAC/D,QAAQ,CAAC,OAAO,EAAE,MAAM,CAAA;IACxB,QAAQ,CAAC,KAAK,CAAC,EAAE,OAAO,CAAA;CACzB,CAAC;CAAG;AAqCL;;;;GAIG;AACH,eAAO,MAAM,gBAAgB,UAAW,MAAM,CAAC,MAAM,EAAE,MAAM,CAAC,IAAI,CAAC,gBAAgB,MAAM,KAAG,UAe3F,CAAA;AAMD,MAAM,WAAW,qBAAqB;IACpC,QAAQ,CAAC,KAAK,EAAE,eAAe,CAAC,eAAe,CAAC,WAAW,CAAC,CAAA;IAC5D,QAAQ,CAAC,OAAO,EAAE,MAAM,CAAC,MAAM,CAAC,IAAI,EAAE,WAAW,CAAC,CAAA;IAClD,QAAQ,CAAC,MAAM,EAAE,CAAC,IAAI,EAAE,MAAM,KAAK,MAAM,CAAC,MAAM,CAAC,aAAa,CAAC,UAAU,CAAC,CAAC,CAAA;CAC5E;;AAED,qBAAa,aAAc,SAAQ,kBAA4E;CAAG;AAElH,eAAO,MAAM,KAAK,kEAkEjB,CAAA"}
@@ -0,0 +1,145 @@
1
+ /**
2
+ * Core timer lifecycle — start, stop, detect running — bridging Clockify and Jira worklog.
3
+ *
4
+ * **Mental model**
5
+ *
6
+ * - **Dual write**: Starting a timer creates a Clockify time entry AND updates the local
7
+ * state file (for Neovim/statusline). Stopping updates the Clockify entry AND posts
8
+ * a Jira worklog through the Schema-validated Jira client.
9
+ * - **Auto-resolution**: Project ID, billable flag, and tags are resolved from config defaults,
10
+ * Clockify project name matching, and Jira issue type/labels.
11
+ * - **External detection**: {@link TimerServiceContract.detectRunning} polls Clockify for a
12
+ * running timer not started by jcf and syncs local state.
13
+ *
14
+ * **Gotchas**
15
+ *
16
+ * - Jira worklog failures remain typed; a 401 is mapped to `NotLoggedIn`.
17
+ * - `timeSpentSeconds` is floored to 60s minimum (Jira rejects <60s worklogs).
18
+ *
19
+ * @module
20
+ */
21
+ import { ClockifyApiClient } from "@knpkv/clockify-api-client";
22
+ import { JiraAuth } from "@knpkv/jira-cli/JiraAuth";
23
+ import * as Context from "effect/Context";
24
+ import * as Duration from "effect/Duration";
25
+ import * as Effect from "effect/Effect";
26
+ import * as FileSystem from "effect/FileSystem";
27
+ import * as HttpClient from "effect/http/HttpClient";
28
+ import * as Layer from "effect/Layer";
29
+ import * as Path from "effect/Path";
30
+ import * as SubscriptionRef from "effect/SubscriptionRef";
31
+ import { ClockifyAuth } from "./ClockifyAuth.js";
32
+ import { ConfigService } from "./ConfigService.js";
33
+ import { StateWriter } from "./StateWriter.js";
34
+ import type { JiraTicket } from "./TicketService.js";
35
+ export interface TimerState {
36
+ readonly active: boolean;
37
+ readonly ticketKey: string | null;
38
+ readonly summary: string | null;
39
+ readonly project: string | null;
40
+ readonly startedAt: Date | null;
41
+ readonly clockifyEntryId: string | null;
42
+ readonly projectId: string | null;
43
+ readonly projectName: string | null;
44
+ /** null = user hasn't explicitly set it (prompt on stop) */
45
+ readonly billable: boolean | null;
46
+ /** true if timer was started via jcf (not just detected from Clockify) */
47
+ readonly startedViaJcf: boolean;
48
+ }
49
+ /** Everything needed to (re)post a Jira worklog without a running timer. */
50
+ export interface WorklogParams {
51
+ readonly ticketKey: string;
52
+ readonly startedAt: Date;
53
+ readonly durationSeconds: number;
54
+ readonly comment?: string | undefined;
55
+ }
56
+ /**
57
+ * Outcome of a single Jira worklog post. Distinguishing these lets callers decide whether a
58
+ * retry is worthwhile and show the user *why* it failed:
59
+ * - `NotLoggedIn` — no usable token; retrying is pointless until `jcf auth jira login`.
60
+ * - `Failed` — Jira rejected the request or the network errored; carries the reason and is retryable.
61
+ */
62
+ export type JiraWorklogOutcome = {
63
+ readonly _tag: "Posted";
64
+ readonly entryId?: string | undefined;
65
+ } | {
66
+ readonly _tag: "NotLoggedIn";
67
+ } | {
68
+ readonly _tag: "Failed";
69
+ readonly message: string;
70
+ };
71
+ export interface StopResult {
72
+ readonly duration: Duration.Duration;
73
+ readonly clockifyLogged: boolean;
74
+ readonly needsProjectId: boolean;
75
+ readonly needsBillable: boolean;
76
+ /** Jira worklog outcome. null when there was no ticket to log against. */
77
+ readonly jiraWorklog: JiraWorklogOutcome | null;
78
+ /**
79
+ * Params to retry the Jira worklog after a partial stop (Clockify saved, Jira failed).
80
+ * Non-null iff {@link jiraWorklog} is `Failed` (the only retryable failure with a ticket).
81
+ */
82
+ readonly worklog: WorklogParams | null;
83
+ }
84
+ declare const TimerError_base: new <A extends Record<string, any> = {}>(args: import("effect/Types").VoidIfEmpty<{ readonly [P in keyof A as P extends "_tag" ? never : P]: A[P]; }>) => import("effect/Cause").YieldableError & {
85
+ readonly _tag: "TimerError";
86
+ } & Readonly<A>;
87
+ export declare class TimerError extends TimerError_base<{
88
+ readonly message: string;
89
+ readonly cause?: unknown;
90
+ }> {
91
+ }
92
+ export interface StartOptions {
93
+ readonly projectId?: string | undefined;
94
+ readonly billable?: boolean | undefined;
95
+ /** Backdate the timer start (e.g. "I forgot to start it 15m ago"). Defaults to now. */
96
+ readonly startedAt?: Date | undefined;
97
+ }
98
+ export interface StopOptions {
99
+ readonly projectId?: string | undefined;
100
+ readonly billable?: boolean | undefined;
101
+ readonly comment?: string | undefined;
102
+ /**
103
+ * End Correction: the real time work stopped, when the user forgot to stop and
104
+ * is pulling the end back from "now". Rejected (not clamped) if out of bounds —
105
+ * see the two-param note on {@link internalStop}. Omit to end at the current time.
106
+ */
107
+ readonly endedAt?: Date | undefined;
108
+ }
109
+ /** A completed interval logged retroactively when the timer was never started. */
110
+ export interface LogManualOptions {
111
+ readonly start: Date;
112
+ readonly durationSeconds: number;
113
+ readonly projectId?: string | undefined;
114
+ readonly billable?: boolean | undefined;
115
+ readonly comment?: string | undefined;
116
+ }
117
+ export interface LogManualResult {
118
+ readonly clockifyLogged: boolean;
119
+ readonly jiraWorklogLogged: boolean;
120
+ readonly projectId: string | null;
121
+ readonly billable: boolean | null;
122
+ }
123
+ export interface TimerServiceContract {
124
+ readonly state: SubscriptionRef.SubscriptionRef<TimerState>;
125
+ readonly start: (ticket: JiraTicket, options?: StartOptions) => Effect.Effect<void, TimerError>;
126
+ readonly stop: (options?: StopOptions) => Effect.Effect<StopResult, TimerError>;
127
+ /**
128
+ * (Re)post a Jira worklog in isolation — used to retry after a partial stop where the
129
+ * Clockify entry saved but the Jira worklog failed. Resolves a {@link JiraWorklogOutcome}
130
+ * so the caller can tell `NotLoggedIn` (don't bother retrying) from a retryable `Failed`
131
+ * and surface the reason. All failures are swallowed into the outcome, so the error channel
132
+ * is honestly `never`.
133
+ */
134
+ readonly logWorklog: (params: WorklogParams) => Effect.Effect<JiraWorklogOutcome>;
135
+ /** Write a completed interval directly (Clockify entry + Jira worklog), no running timer involved. */
136
+ readonly logManual: (ticket: JiraTicket, options: LogManualOptions) => Effect.Effect<LogManualResult, TimerError>;
137
+ readonly discard: Effect.Effect<void, TimerError>;
138
+ readonly detectRunning: Effect.Effect<void, TimerError>;
139
+ }
140
+ declare const TimerService_base: Context.ServiceClass<TimerService, "jcf/TimerService", TimerServiceContract>;
141
+ export declare class TimerService extends TimerService_base {
142
+ }
143
+ export declare const layer: Layer.Layer<TimerService, never, ClockifyApiClient | ClockifyAuth | ConfigService | FileSystem.FileSystem | HttpClient.HttpClient | JiraAuth | Path.Path | StateWriter>;
144
+ export {};
145
+ //# sourceMappingURL=TimerService.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"TimerService.d.ts","sourceRoot":"","sources":["../../../src/services/TimerService.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;;GAmBG;AACH,OAAO,EAAE,iBAAiB,EAAE,MAAM,4BAA4B,CAAA;AAE9D,OAAO,EAAE,QAAQ,EAAE,MAAM,0BAA0B,CAAA;AAEnD,OAAO,KAAK,OAAO,MAAM,gBAAgB,CAAA;AAGzC,OAAO,KAAK,QAAQ,MAAM,iBAAiB,CAAA;AAC3C,OAAO,KAAK,MAAM,MAAM,eAAe,CAAA;AACvC,OAAO,KAAK,UAAU,MAAM,mBAAmB,CAAA;AAC/C,OAAO,KAAK,UAAU,MAAM,wBAAwB,CAAA;AACpD,OAAO,KAAK,KAAK,MAAM,cAAc,CAAA;AAErC,OAAO,KAAK,IAAI,MAAM,aAAa,CAAA;AAGnC,OAAO,KAAK,eAAe,MAAM,wBAAwB,CAAA;AAEzD,OAAO,EAAE,YAAY,EAAE,MAAM,mBAAmB,CAAA;AAChD,OAAO,EAAE,aAAa,EAAE,MAAM,oBAAoB,CAAA;AAElD,OAAO,EAAE,WAAW,EAAuB,MAAM,kBAAkB,CAAA;AACnE,OAAO,KAAK,EAAE,UAAU,EAAE,MAAM,oBAAoB,CAAA;AAMpD,MAAM,WAAW,UAAU;IACzB,QAAQ,CAAC,MAAM,EAAE,OAAO,CAAA;IACxB,QAAQ,CAAC,SAAS,EAAE,MAAM,GAAG,IAAI,CAAA;IACjC,QAAQ,CAAC,OAAO,EAAE,MAAM,GAAG,IAAI,CAAA;IAC/B,QAAQ,CAAC,OAAO,EAAE,MAAM,GAAG,IAAI,CAAA;IAC/B,QAAQ,CAAC,SAAS,EAAE,IAAI,GAAG,IAAI,CAAA;IAC/B,QAAQ,CAAC,eAAe,EAAE,MAAM,GAAG,IAAI,CAAA;IACvC,QAAQ,CAAC,SAAS,EAAE,MAAM,GAAG,IAAI,CAAA;IACjC,QAAQ,CAAC,WAAW,EAAE,MAAM,GAAG,IAAI,CAAA;IACnC,4DAA4D;IAC5D,QAAQ,CAAC,QAAQ,EAAE,OAAO,GAAG,IAAI,CAAA;IACjC,0EAA0E;IAC1E,QAAQ,CAAC,aAAa,EAAE,OAAO,CAAA;CAChC;AAED,4EAA4E;AAC5E,MAAM,WAAW,aAAa;IAC5B,QAAQ,CAAC,SAAS,EAAE,MAAM,CAAA;IAC1B,QAAQ,CAAC,SAAS,EAAE,IAAI,CAAA;IACxB,QAAQ,CAAC,eAAe,EAAE,MAAM,CAAA;IAChC,QAAQ,CAAC,OAAO,CAAC,EAAE,MAAM,GAAG,SAAS,CAAA;CACtC;AAED;;;;;GAKG;AACH,MAAM,MAAM,kBAAkB,GAC1B;IAAE,QAAQ,CAAC,IAAI,EAAE,QAAQ,CAAC;IAAC,QAAQ,CAAC,OAAO,CAAC,EAAE,MAAM,GAAG,SAAS,CAAA;CAAE,GAClE;IAAE,QAAQ,CAAC,IAAI,EAAE,aAAa,CAAA;CAAE,GAChC;IAAE,QAAQ,CAAC,IAAI,EAAE,QAAQ,CAAC;IAAC,QAAQ,CAAC,OAAO,EAAE,MAAM,CAAA;CAAE,CAAA;AAEzD,MAAM,WAAW,UAAU;IACzB,QAAQ,CAAC,QAAQ,EAAE,QAAQ,CAAC,QAAQ,CAAA;IACpC,QAAQ,CAAC,cAAc,EAAE,OAAO,CAAA;IAChC,QAAQ,CAAC,cAAc,EAAE,OAAO,CAAA;IAChC,QAAQ,CAAC,aAAa,EAAE,OAAO,CAAA;IAC/B,0EAA0E;IAC1E,QAAQ,CAAC,WAAW,EAAE,kBAAkB,GAAG,IAAI,CAAA;IAC/C;;;OAGG;IACH,QAAQ,CAAC,OAAO,EAAE,aAAa,GAAG,IAAI,CAAA;CACvC;;;;AAED,qBAAa,UAAW,SAAQ,gBAA+B;IAC7D,QAAQ,CAAC,OAAO,EAAE,MAAM,CAAA;IACxB,QAAQ,CAAC,KAAK,CAAC,EAAE,OAAO,CAAA;CACzB,CAAC;CAAG;AAmBL,MAAM,WAAW,YAAY;IAC3B,QAAQ,CAAC,SAAS,CAAC,EAAE,MAAM,GAAG,SAAS,CAAA;IACvC,QAAQ,CAAC,QAAQ,CAAC,EAAE,OAAO,GAAG,SAAS,CAAA;IACvC,uFAAuF;IACvF,QAAQ,CAAC,SAAS,CAAC,EAAE,IAAI,GAAG,SAAS,CAAA;CACtC;AAED,MAAM,WAAW,WAAW;IAC1B,QAAQ,CAAC,SAAS,CAAC,EAAE,MAAM,GAAG,SAAS,CAAA;IACvC,QAAQ,CAAC,QAAQ,CAAC,EAAE,OAAO,GAAG,SAAS,CAAA;IACvC,QAAQ,CAAC,OAAO,CAAC,EAAE,MAAM,GAAG,SAAS,CAAA;IACrC;;;;OAIG;IACH,QAAQ,CAAC,OAAO,CAAC,EAAE,IAAI,GAAG,SAAS,CAAA;CACpC;AAED,kFAAkF;AAClF,MAAM,WAAW,gBAAgB;IAC/B,QAAQ,CAAC,KAAK,EAAE,IAAI,CAAA;IACpB,QAAQ,CAAC,eAAe,EAAE,MAAM,CAAA;IAChC,QAAQ,CAAC,SAAS,CAAC,EAAE,MAAM,GAAG,SAAS,CAAA;IACvC,QAAQ,CAAC,QAAQ,CAAC,EAAE,OAAO,GAAG,SAAS,CAAA;IACvC,QAAQ,CAAC,OAAO,CAAC,EAAE,MAAM,GAAG,SAAS,CAAA;CACtC;AAED,MAAM,WAAW,eAAe;IAC9B,QAAQ,CAAC,cAAc,EAAE,OAAO,CAAA;IAChC,QAAQ,CAAC,iBAAiB,EAAE,OAAO,CAAA;IACnC,QAAQ,CAAC,SAAS,EAAE,MAAM,GAAG,IAAI,CAAA;IACjC,QAAQ,CAAC,QAAQ,EAAE,OAAO,GAAG,IAAI,CAAA;CAClC;AAED,MAAM,WAAW,oBAAoB;IACnC,QAAQ,CAAC,KAAK,EAAE,eAAe,CAAC,eAAe,CAAC,UAAU,CAAC,CAAA;IAC3D,QAAQ,CAAC,KAAK,EAAE,CAAC,MAAM,EAAE,UAAU,EAAE,OAAO,CAAC,EAAE,YAAY,KAAK,MAAM,CAAC,MAAM,CAAC,IAAI,EAAE,UAAU,CAAC,CAAA;IAC/F,QAAQ,CAAC,IAAI,EAAE,CAAC,OAAO,CAAC,EAAE,WAAW,KAAK,MAAM,CAAC,MAAM,CAAC,UAAU,EAAE,UAAU,CAAC,CAAA;IAC/E;;;;;;OAMG;IACH,QAAQ,CAAC,UAAU,EAAE,CAAC,MAAM,EAAE,aAAa,KAAK,MAAM,CAAC,MAAM,CAAC,kBAAkB,CAAC,CAAA;IACjF,sGAAsG;IACtG,QAAQ,CAAC,SAAS,EAAE,CAAC,MAAM,EAAE,UAAU,EAAE,OAAO,EAAE,gBAAgB,KAAK,MAAM,CAAC,MAAM,CAAC,eAAe,EAAE,UAAU,CAAC,CAAA;IACjH,QAAQ,CAAC,OAAO,EAAE,MAAM,CAAC,MAAM,CAAC,IAAI,EAAE,UAAU,CAAC,CAAA;IACjD,QAAQ,CAAC,aAAa,EAAE,MAAM,CAAC,MAAM,CAAC,IAAI,EAAE,UAAU,CAAC,CAAA;CACxD;;AAED,qBAAa,YAAa,SAAQ,iBAAyE;CAAG;AAE9G,eAAO,MAAM,KAAK,yKA0djB,CAAA"}