@knpkv/jira-clockify 1.3.0 → 1.4.1

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 (242) hide show
  1. package/README.md +245 -1
  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 +57 -13
  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 +3 -3
  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/package.json +36 -18
  242. package/skills/jcf/SKILL.md +93 -1
@@ -0,0 +1,154 @@
1
+ import type { CreditedBlock, CreditedSpan } from "./sessions.js";
2
+ /** The provider scope explicitly selected by the caller. */
3
+ export interface WriteTargets {
4
+ readonly clockify: boolean;
5
+ readonly jira: boolean;
6
+ }
7
+ /** Concrete provider arguments. Zero seconds means this side has no write. */
8
+ export interface SideWrite {
9
+ readonly seconds: number;
10
+ /** Owed seconds that cannot be represented by this provider's minimum segment size. */
11
+ readonly withheldSeconds?: number | undefined;
12
+ /** A safety hold on selected source blocks; not an amount already logged. */
13
+ readonly refusal?: "unlinked-overlap" | undefined;
14
+ readonly startedAt: Date | undefined;
15
+ /** Uncovered source pieces to write in order; kept separate across recorded gaps and blocks. */
16
+ readonly segments: ReadonlyArray<{
17
+ readonly block: CreditedBlock;
18
+ readonly seconds: number;
19
+ readonly startedAt: Date;
20
+ /** Provider-visible description override for this exact segment. */
21
+ readonly description?: string | undefined;
22
+ }>;
23
+ }
24
+ /** Sizing and anchoring are finished before a provider executes this plan. */
25
+ export interface PlannedWrite {
26
+ readonly _tag: "Write";
27
+ readonly ticketKey: string;
28
+ readonly day: string;
29
+ readonly targets: WriteTargets;
30
+ readonly clockify: SideWrite;
31
+ readonly jira: SideWrite;
32
+ }
33
+ interface RecordedBucket {
34
+ readonly ticketKey: string;
35
+ readonly day: string;
36
+ readonly clockifySeconds: number;
37
+ readonly jiraSeconds: number;
38
+ readonly intervals: ReadonlyArray<{
39
+ readonly startMs: number;
40
+ readonly endMs: number;
41
+ readonly source: "clockify" | "jira";
42
+ }>;
43
+ }
44
+ export type PreparedProposal = {
45
+ readonly _tag: "UnknownBlocks";
46
+ } | {
47
+ readonly _tag: "NoTargets";
48
+ } | {
49
+ readonly _tag: "Prepared";
50
+ readonly ticketKey: string;
51
+ readonly day: string;
52
+ readonly targets: WriteTargets;
53
+ readonly provenance: {
54
+ readonly evidence: "session";
55
+ readonly amountSetByHand: boolean;
56
+ readonly ticketSetByHand: boolean;
57
+ };
58
+ readonly plan: (recorded: ReadonlyArray<RecordedBucket>) => PlannedWrite | Exclude<ProposedWrite, {
59
+ readonly _tag: "Write";
60
+ }>;
61
+ };
62
+ /**
63
+ * Resolve the selected evidence before reading providers, then plan against their answers.
64
+ * Server callers supply fresh totals; previews supply cached totals. Neither caller computes
65
+ * selection credit or anchors. A selected subset starts where the person pointed; a whole row
66
+ * advances past each provider's recorded time. No evidence or provider state is mutated.
67
+ */
68
+ export declare const prepareProposal: (options: {
69
+ readonly evidence: {
70
+ readonly blocks: ReadonlyArray<CreditedBlock>;
71
+ readonly credited: number;
72
+ readonly ticketKey: string;
73
+ readonly day: string;
74
+ };
75
+ readonly request: {
76
+ readonly blocks?: ReadonlyArray<number> | undefined;
77
+ readonly seconds?: number | undefined;
78
+ readonly ticketKey?: string | undefined;
79
+ readonly targets?: WriteTargets | undefined;
80
+ };
81
+ readonly targets: WriteTargets;
82
+ /** Server-retained source credit already written under a corrected ticket. */
83
+ readonly consumed?: ((block: CreditedBlock, source: "clockify" | "jira") => number) | undefined;
84
+ }) => PreparedProposal;
85
+ /**
86
+ * The blocks a confirmation named, or every block when it named none.
87
+ *
88
+ * `undefined` for an index that is not a block of this row: a stale page confirming against a plan
89
+ * that has been re-read is a case to refuse, not to write a guess for.
90
+ */
91
+ export declare const selectedBlocks: (blocks: ReadonlyArray<CreditedBlock>, chosen: ReadonlyArray<number> | undefined) => ReadonlyArray<CreditedBlock> | undefined;
92
+ /**
93
+ * What accepting a row would write, given a live re-tally of the target bucket.
94
+ *
95
+ * Every number here is the server's: `credited` is the evidence the plan was built from, `selected`
96
+ * is the part of it a person is accepting now, and `held` is what the two systems answered a moment
97
+ * ago. `requested` is the only input a person supplies, and it is capped by the selection rather
98
+ * than clamped to it — silently writing less than someone asked for is its own kind of wrong.
99
+ *
100
+ * **Why a side is sized against the whole row and not against the selection.** `credited - held` is
101
+ * the room left in the day; the selection only says how much of that room to use now. Sizing a
102
+ * block against `selected - held` instead would report "already logged" for the second block of any
103
+ * row whose first block is already in — the arithmetic would treat the morning's entry as evidence
104
+ * that the afternoon had been written too.
105
+ */
106
+ export type ProposedWrite = {
107
+ readonly _tag: "Write";
108
+ readonly clockifyDelta: number;
109
+ readonly jiraDelta: number;
110
+ } | {
111
+ readonly _tag: "NothingOwed";
112
+ } | {
113
+ readonly _tag: "PastEvidence";
114
+ readonly maxSeconds: number;
115
+ } | {
116
+ readonly _tag: "BelowMinimum";
117
+ readonly minimumSeconds: number;
118
+ };
119
+ /**
120
+ * Jira's minimum worklog duration. Clockify retains exact positive seconds below this floor.
121
+ */
122
+ export declare const MINIMUM_WRITE_SECONDS = 60;
123
+ export declare const proposeWrite: (options: {
124
+ readonly credited: number;
125
+ /** The blocks being accepted now. Defaults to the whole row. */
126
+ readonly selected?: number | undefined;
127
+ readonly requested: number | undefined;
128
+ readonly heldClockifySeconds: number;
129
+ readonly heldJiraSeconds: number;
130
+ /** Provider time already overlapping this selection. Omitted for a whole-row write. */
131
+ readonly heldSelectedClockifySeconds?: number | undefined;
132
+ readonly heldSelectedJiraSeconds?: number | undefined;
133
+ /** Which systems are in play. A side that is out gets a zero delta, never a gap. */
134
+ readonly targets?: {
135
+ readonly clockify: boolean;
136
+ readonly jira: boolean;
137
+ } | undefined;
138
+ }) => ProposedWrite;
139
+ /**
140
+ * Where a write should say the work began, given what that side already holds.
141
+ *
142
+ * A proposal covers a whole `(Issue Key, day)` bucket, but the amount written is only the gap. Under
143
+ * `jcf watch` that gap arrives block by block: the morning is written when it settles, and the
144
+ * afternoon follows as its own write against the same bucket. Anchoring both at the bucket's first
145
+ * instant would file the afternoon's hours at 09:00 — a second Clockify entry laid directly over the
146
+ * first, and a Jira worklog dated to work that had not started yet.
147
+ *
148
+ * So the anchor skips the blocks that side already accounts for and starts at the first one it does
149
+ * not. Approximate where work ran in parallel, because `seconds` is a *share* of those blocks rather
150
+ * than their wall clock — but the error is then bounded by one block, against a whole day before.
151
+ */
152
+ export declare const writeAnchor: (spans: ReadonlyArray<CreditedSpan>, alreadyRecordedSeconds: number) => Date | undefined;
153
+ export {};
154
+ //# sourceMappingURL=writePlanning.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"writePlanning.d.ts","sourceRoot":"","sources":["../../../src/agent/writePlanning.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,210 @@
1
+ import * as SourceConsumption from "./sourceConsumption.js";
2
+ /** Recorded seconds that overlap the selected evidence, unioned per block and capped by its credit. */
3
+ const recordedIn = (blocks, intervals, source) => blocks.reduce((total, block) => total + SourceConsumption.recordedSecondsInBlock(block, intervals, source), 0);
4
+ /** Wall-clock pieces of one block not covered by this provider's existing target-bucket entries. */
5
+ const uncovered = (block, intervals, source) => {
6
+ const covered = intervals
7
+ .filter((interval) => interval.source === source)
8
+ .map((interval) => ({
9
+ startMs: Math.max(block.startMs, interval.startMs),
10
+ endMs: Math.min(block.endMs, interval.endMs)
11
+ }))
12
+ .filter((interval) => interval.endMs > interval.startMs)
13
+ .sort((a, b) => a.startMs - b.startMs);
14
+ const result = [];
15
+ let cursor = block.startMs;
16
+ for (const interval of covered) {
17
+ if (interval.startMs > cursor)
18
+ result.push({ startMs: cursor, endMs: interval.startMs });
19
+ cursor = Math.max(cursor, interval.endMs);
20
+ }
21
+ if (cursor < block.endMs)
22
+ result.push({ startMs: cursor, endMs: block.endMs });
23
+ return result;
24
+ };
25
+ /**
26
+ * Resolve the selected evidence before reading providers, then plan against their answers.
27
+ * Server callers supply fresh totals; previews supply cached totals. Neither caller computes
28
+ * selection credit or anchors. A selected subset starts where the person pointed; a whole row
29
+ * advances past each provider's recorded time. No evidence or provider state is mutated.
30
+ */
31
+ export const prepareProposal = (options) => {
32
+ const { evidence, request } = options;
33
+ const blocks = selectedBlocks(evidence.blocks, request.blocks);
34
+ if (blocks === undefined)
35
+ return { _tag: "UnknownBlocks" };
36
+ const targets = request.targets ?? options.targets;
37
+ if (!targets.clockify && !targets.jira)
38
+ return { _tag: "NoTargets" };
39
+ const selected = blocks.reduce((sum, block) => sum + block.seconds, 0);
40
+ const ticketKey = request.ticketKey ?? evidence.ticketKey;
41
+ return {
42
+ _tag: "Prepared",
43
+ ticketKey,
44
+ day: evidence.day,
45
+ targets,
46
+ provenance: {
47
+ evidence: "session",
48
+ amountSetByHand: request.seconds !== undefined && request.seconds !== selected,
49
+ ticketSetByHand: ticketKey !== evidence.ticketKey
50
+ },
51
+ plan: (recorded) => {
52
+ const bucket = recorded.find((row) => row.ticketKey === ticketKey && row.day === evidence.day);
53
+ const correctedBeyondTarget = (source) => evidence.blocks.reduce((total, block) => total + Math.max(0, (options.consumed?.(block, source) ?? 0) - recordedIn([block], bucket?.intervals ?? [], source)), 0);
54
+ const heldClockifySeconds = (bucket?.clockifySeconds ?? 0) + correctedBeyondTarget("clockify");
55
+ const heldJiraSeconds = (bucket?.jiraSeconds ?? 0) + correctedBeyondTarget("jira");
56
+ const heldInSelection = (source) => blocks.reduce((total, block) => total + Math.max(recordedIn([block], bucket?.intervals ?? [], source), options.consumed?.(block, source) ?? 0), 0);
57
+ const heldSelectedClockifySeconds = heldInSelection("clockify");
58
+ const heldSelectedJiraSeconds = heldInSelection("jira");
59
+ const sized = proposeWrite({
60
+ credited: evidence.credited,
61
+ selected,
62
+ requested: request.seconds,
63
+ heldClockifySeconds,
64
+ heldJiraSeconds,
65
+ heldSelectedClockifySeconds,
66
+ heldSelectedJiraSeconds,
67
+ targets
68
+ });
69
+ if (sized._tag !== "Write")
70
+ return sized;
71
+ const side = (seconds, source) => {
72
+ let remaining = seconds;
73
+ let refused = false;
74
+ const segments = [];
75
+ for (const block of blocks) {
76
+ if (remaining <= 0)
77
+ break;
78
+ const recorded = recordedIn([block], bucket?.intervals ?? [], source);
79
+ const consumed = options.consumed?.(block, source) ?? 0;
80
+ let skip = Math.max(0, consumed - recorded);
81
+ let availableCredit = Math.max(0, block.seconds - Math.max(recorded, consumed));
82
+ if (source === "clockify" && block.clockifyRefusal === "unlinked-overlap" && availableCredit > 0) {
83
+ refused = true;
84
+ continue;
85
+ }
86
+ for (const range of uncovered(block, bucket?.intervals ?? [], source)) {
87
+ const rangeSeconds = (range.endMs - range.startMs) / 1000;
88
+ const skipped = Math.min(skip, rangeSeconds);
89
+ skip -= skipped;
90
+ const capacity = Math.min(rangeSeconds - skipped, availableCredit);
91
+ const allocated = Math.min(remaining, capacity);
92
+ if (allocated > 0) {
93
+ // Jira rounds every worklog up to its one-minute floor. A shorter executable segment
94
+ // would write more than this evidence permits, even when several short gaps total a
95
+ // minute, so it must stay withheld.
96
+ if (source === "jira" && allocated < MINIMUM_WRITE_SECONDS)
97
+ continue;
98
+ segments.push({
99
+ block,
100
+ seconds: allocated,
101
+ startedAt: new Date(range.startMs + skipped * 1000)
102
+ });
103
+ remaining -= allocated;
104
+ availableCredit -= allocated;
105
+ }
106
+ }
107
+ }
108
+ const executableSeconds = segments.reduce((sum, segment) => sum + segment.seconds, 0);
109
+ return {
110
+ seconds: executableSeconds,
111
+ withheldSeconds: Math.max(0, seconds - executableSeconds),
112
+ ...(refused && { refusal: "unlinked-overlap" }),
113
+ segments,
114
+ startedAt: segments[0]?.startedAt
115
+ };
116
+ };
117
+ const clockify = side(sized.clockifyDelta, "clockify");
118
+ const jira = side(sized.jiraDelta, "jira");
119
+ if (clockify.seconds === 0 && jira.seconds === 0 && clockify.refusal === undefined) {
120
+ return { _tag: "BelowMinimum", minimumSeconds: MINIMUM_WRITE_SECONDS };
121
+ }
122
+ return {
123
+ _tag: "Write",
124
+ ticketKey,
125
+ day: evidence.day,
126
+ targets,
127
+ clockify,
128
+ jira
129
+ };
130
+ }
131
+ };
132
+ };
133
+ /**
134
+ * The blocks a confirmation named, or every block when it named none.
135
+ *
136
+ * `undefined` for an index that is not a block of this row: a stale page confirming against a plan
137
+ * that has been re-read is a case to refuse, not to write a guess for.
138
+ */
139
+ export const selectedBlocks = (blocks, chosen) => {
140
+ if (chosen === undefined)
141
+ return blocks;
142
+ const picked = [];
143
+ for (const index of [...new Set(chosen)].sort((a, b) => a - b)) {
144
+ const block = blocks[index];
145
+ if (block === undefined)
146
+ return undefined;
147
+ picked.push(block);
148
+ }
149
+ return picked.length === 0 ? undefined : picked;
150
+ };
151
+ /**
152
+ * Jira's minimum worklog duration. Clockify retains exact positive seconds below this floor.
153
+ */
154
+ export const MINIMUM_WRITE_SECONDS = 60;
155
+ export const proposeWrite = (options) => {
156
+ const targets = options.targets ?? { clockify: true, jira: true };
157
+ const selected = Math.min(options.selected ?? options.credited, options.credited);
158
+ const requested = options.requested ?? selected;
159
+ if (requested > selected)
160
+ return { _tag: "PastEvidence", maxSeconds: selected };
161
+ if (requested < (targets.clockify ? 1 : MINIMUM_WRITE_SECONDS)) {
162
+ return { _tag: "BelowMinimum", minimumSeconds: targets.clockify ? 1 : MINIMUM_WRITE_SECONDS };
163
+ }
164
+ const owed = (held, heldSelected, asked, minimum) => {
165
+ if (!asked)
166
+ return 0;
167
+ // Room left in the day, then as much of it as this selection asks for.
168
+ const room = Math.max(0, options.credited - held);
169
+ const delta = Math.min(Math.max(0, requested - heldSelected), room);
170
+ return delta < minimum ? 0 : delta;
171
+ };
172
+ const clockifyDelta = owed(options.heldClockifySeconds, options.heldSelectedClockifySeconds ?? 0, targets.clockify, 1);
173
+ const jiraDelta = owed(options.heldJiraSeconds, options.heldSelectedJiraSeconds ?? 0, targets.jira, MINIMUM_WRITE_SECONDS);
174
+ // Nothing left on either side asked for: the ordinary outcome of confirming a row twice, or of a
175
+ // watch having taken it in between. Not a failure, and not a write.
176
+ if (clockifyDelta === 0 && jiraDelta === 0)
177
+ return { _tag: "NothingOwed" };
178
+ return { _tag: "Write", clockifyDelta, jiraDelta };
179
+ };
180
+ /**
181
+ * Where a write should say the work began, given what that side already holds.
182
+ *
183
+ * A proposal covers a whole `(Issue Key, day)` bucket, but the amount written is only the gap. Under
184
+ * `jcf watch` that gap arrives block by block: the morning is written when it settles, and the
185
+ * afternoon follows as its own write against the same bucket. Anchoring both at the bucket's first
186
+ * instant would file the afternoon's hours at 09:00 — a second Clockify entry laid directly over the
187
+ * first, and a Jira worklog dated to work that had not started yet.
188
+ *
189
+ * So the anchor skips the blocks that side already accounts for and starts at the first one it does
190
+ * not. Approximate where work ran in parallel, because `seconds` is a *share* of those blocks rather
191
+ * than their wall clock — but the error is then bounded by one block, against a whole day before.
192
+ */
193
+ export const writeAnchor = (spans, alreadyRecordedSeconds) => {
194
+ const ordered = [...spans].sort((a, b) => a.startMs - b.startMs);
195
+ let remaining = alreadyRecordedSeconds;
196
+ for (const span of ordered) {
197
+ const seconds = (span.endMs - span.startMs) / 1000;
198
+ if (remaining >= seconds) {
199
+ remaining -= seconds;
200
+ continue;
201
+ }
202
+ return new Date(span.startMs + remaining * 1000);
203
+ }
204
+ // Every block is already spoken for. Reached only when a side is not short, so nothing is written
205
+ // with this anchor — but the end of the last block is the one instant that cannot overlap what is
206
+ // already recorded, where the first block is the one instant guaranteed to.
207
+ const last = ordered[ordered.length - 1];
208
+ return last === undefined ? undefined : new Date(last.endMs);
209
+ };
210
+ //# sourceMappingURL=writePlanning.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"writePlanning.js","sourceRoot":"","sources":["../../../src/agent/writePlanning.ts"],"names":[],"mappings":"AACA,OAAO,KAAK,iBAAiB,MAAM,wBAAwB,CAAA;AAgD3D,uGAAuG;AACvG,MAAM,UAAU,GAAG,CACjB,MAAoC,EACpC,SAAsC,EACtC,MAA2B,EACnB,EAAE,CACV,MAAM,CAAC,MAAM,CACX,CAAC,KAAK,EAAE,KAAK,EAAE,EAAE,CAAC,KAAK,GAAG,iBAAiB,CAAC,sBAAsB,CAAC,KAAK,EAAE,SAAS,EAAE,MAAM,CAAC,EAC5F,CAAC,CACF,CAAA;AAEH,oGAAoG;AACpG,MAAM,SAAS,GAAG,CAChB,KAAoB,EACpB,SAAsC,EACtC,MAA2B,EAC0C,EAAE;IACvE,MAAM,OAAO,GAAG,SAAS;SACtB,MAAM,CAAC,CAAC,QAAQ,EAAE,EAAE,CAAC,QAAQ,CAAC,MAAM,KAAK,MAAM,CAAC;SAChD,GAAG,CAAC,CAAC,QAAQ,EAAE,EAAE,CAAC,CAAC;QAClB,OAAO,EAAE,IAAI,CAAC,GAAG,CAAC,KAAK,CAAC,OAAO,EAAE,QAAQ,CAAC,OAAO,CAAC;QAClD,KAAK,EAAE,IAAI,CAAC,GAAG,CAAC,KAAK,CAAC,KAAK,EAAE,QAAQ,CAAC,KAAK,CAAC;KAC7C,CAAC,CAAC;SACF,MAAM,CAAC,CAAC,QAAQ,EAAE,EAAE,CAAC,QAAQ,CAAC,KAAK,GAAG,QAAQ,CAAC,OAAO,CAAC;SACvD,IAAI,CAAC,CAAC,CAAC,EAAE,CAAC,EAAE,EAAE,CAAC,CAAC,CAAC,OAAO,GAAG,CAAC,CAAC,OAAO,CAAC,CAAA;IACxC,MAAM,MAAM,GAA8C,EAAE,CAAA;IAC5D,IAAI,MAAM,GAAG,KAAK,CAAC,OAAO,CAAA;IAC1B,KAAK,MAAM,QAAQ,IAAI,OAAO,EAAE,CAAC;QAC/B,IAAI,QAAQ,CAAC,OAAO,GAAG,MAAM;YAAE,MAAM,CAAC,IAAI,CAAC,EAAE,OAAO,EAAE,MAAM,EAAE,KAAK,EAAE,QAAQ,CAAC,OAAO,EAAE,CAAC,CAAA;QACxF,MAAM,GAAG,IAAI,CAAC,GAAG,CAAC,MAAM,EAAE,QAAQ,CAAC,KAAK,CAAC,CAAA;IAC3C,CAAC;IACD,IAAI,MAAM,GAAG,KAAK,CAAC,KAAK;QAAE,MAAM,CAAC,IAAI,CAAC,EAAE,OAAO,EAAE,MAAM,EAAE,KAAK,EAAE,KAAK,CAAC,KAAK,EAAE,CAAC,CAAA;IAC9E,OAAO,MAAM,CAAA;AACf,CAAC,CAAA;AAoBD;;;;;GAKG;AACH,MAAM,CAAC,MAAM,eAAe,GAAG,CAAC,OAgB/B,EAAoB,EAAE;IACrB,MAAM,EAAE,QAAQ,EAAE,OAAO,EAAE,GAAG,OAAO,CAAA;IACrC,MAAM,MAAM,GAAG,cAAc,CAAC,QAAQ,CAAC,MAAM,EAAE,OAAO,CAAC,MAAM,CAAC,CAAA;IAC9D,IAAI,MAAM,KAAK,SAAS;QAAE,OAAO,EAAE,IAAI,EAAE,eAAe,EAAE,CAAA;IAC1D,MAAM,OAAO,GAAG,OAAO,CAAC,OAAO,IAAI,OAAO,CAAC,OAAO,CAAA;IAClD,IAAI,CAAC,OAAO,CAAC,QAAQ,IAAI,CAAC,OAAO,CAAC,IAAI;QAAE,OAAO,EAAE,IAAI,EAAE,WAAW,EAAE,CAAA;IACpE,MAAM,QAAQ,GAAG,MAAM,CAAC,MAAM,CAAC,CAAC,GAAG,EAAE,KAAK,EAAE,EAAE,CAAC,GAAG,GAAG,KAAK,CAAC,OAAO,EAAE,CAAC,CAAC,CAAA;IACtE,MAAM,SAAS,GAAG,OAAO,CAAC,SAAS,IAAI,QAAQ,CAAC,SAAS,CAAA;IACzD,OAAO;QACL,IAAI,EAAE,UAAU;QAChB,SAAS;QACT,GAAG,EAAE,QAAQ,CAAC,GAAG;QACjB,OAAO;QACP,UAAU,EAAE;YACV,QAAQ,EAAE,SAAS;YACnB,eAAe,EAAE,OAAO,CAAC,OAAO,KAAK,SAAS,IAAI,OAAO,CAAC,OAAO,KAAK,QAAQ;YAC9E,eAAe,EAAE,SAAS,KAAK,QAAQ,CAAC,SAAS;SAClD;QACD,IAAI,EAAE,CACJ,QAAuC,EAC4B,EAAE;YACrE,MAAM,MAAM,GAAG,QAAQ,CAAC,IAAI,CAAC,CAAC,GAAG,EAAE,EAAE,CAAC,GAAG,CAAC,SAAS,KAAK,SAAS,IAAI,GAAG,CAAC,GAAG,KAAK,QAAQ,CAAC,GAAG,CAAC,CAAA;YAC9F,MAAM,qBAAqB,GAAG,CAAC,MAA2B,EAAU,EAAE,CACpE,QAAQ,CAAC,MAAM,CAAC,MAAM,CAAC,CAAC,KAAK,EAAE,KAAK,EAAE,EAAE,CACtC,KAAK,GAAG,IAAI,CAAC,GAAG,CACd,CAAC,EACD,CAAC,OAAO,CAAC,QAAQ,EAAE,CAAC,KAAK,EAAE,MAAM,CAAC,IAAI,CAAC,CAAC,GAAG,UAAU,CAAC,CAAC,KAAK,CAAC,EAAE,MAAM,EAAE,SAAS,IAAI,EAAE,EAAE,MAAM,CAAC,CAChG,EAAE,CAAC,CAAC,CAAA;YACT,MAAM,mBAAmB,GAAG,CAAC,MAAM,EAAE,eAAe,IAAI,CAAC,CAAC,GAAG,qBAAqB,CAAC,UAAU,CAAC,CAAA;YAC9F,MAAM,eAAe,GAAG,CAAC,MAAM,EAAE,WAAW,IAAI,CAAC,CAAC,GAAG,qBAAqB,CAAC,MAAM,CAAC,CAAA;YAClF,MAAM,eAAe,GAAG,CAAC,MAA2B,EAAU,EAAE,CAC9D,MAAM,CAAC,MAAM,CAAC,CAAC,KAAK,EAAE,KAAK,EAAE,EAAE,CAC7B,KAAK,GAAG,IAAI,CAAC,GAAG,CACd,UAAU,CAAC,CAAC,KAAK,CAAC,EAAE,MAAM,EAAE,SAAS,IAAI,EAAE,EAAE,MAAM,CAAC,EACpD,OAAO,CAAC,QAAQ,EAAE,CAAC,KAAK,EAAE,MAAM,CAAC,IAAI,CAAC,CACvC,EAAE,CAAC,CAAC,CAAA;YACT,MAAM,2BAA2B,GAAG,eAAe,CAAC,UAAU,CAAC,CAAA;YAC/D,MAAM,uBAAuB,GAAG,eAAe,CAAC,MAAM,CAAC,CAAA;YACvD,MAAM,KAAK,GAAG,YAAY,CAAC;gBACzB,QAAQ,EAAE,QAAQ,CAAC,QAAQ;gBAC3B,QAAQ;gBACR,SAAS,EAAE,OAAO,CAAC,OAAO;gBAC1B,mBAAmB;gBACnB,eAAe;gBACf,2BAA2B;gBAC3B,uBAAuB;gBACvB,OAAO;aACR,CAAC,CAAA;YACF,IAAI,KAAK,CAAC,IAAI,KAAK,OAAO;gBAAE,OAAO,KAAK,CAAA;YACxC,MAAM,IAAI,GAAG,CAAC,OAAe,EAAE,MAA2B,EAAa,EAAE;gBACvE,IAAI,SAAS,GAAG,OAAO,CAAA;gBACvB,IAAI,OAAO,GAAG,KAAK,CAAA;gBACnB,MAAM,QAAQ,GAAsE,EAAE,CAAA;gBACtF,KAAK,MAAM,KAAK,IAAI,MAAM,EAAE,CAAC;oBAC3B,IAAI,SAAS,IAAI,CAAC;wBAAE,MAAK;oBACzB,MAAM,QAAQ,GAAG,UAAU,CAAC,CAAC,KAAK,CAAC,EAAE,MAAM,EAAE,SAAS,IAAI,EAAE,EAAE,MAAM,CAAC,CAAA;oBACrE,MAAM,QAAQ,GAAG,OAAO,CAAC,QAAQ,EAAE,CAAC,KAAK,EAAE,MAAM,CAAC,IAAI,CAAC,CAAA;oBACvD,IAAI,IAAI,GAAG,IAAI,CAAC,GAAG,CAAC,CAAC,EAAE,QAAQ,GAAG,QAAQ,CAAC,CAAA;oBAC3C,IAAI,eAAe,GAAG,IAAI,CAAC,GAAG,CAAC,CAAC,EAAE,KAAK,CAAC,OAAO,GAAG,IAAI,CAAC,GAAG,CAAC,QAAQ,EAAE,QAAQ,CAAC,CAAC,CAAA;oBAC/E,IAAI,MAAM,KAAK,UAAU,IAAI,KAAK,CAAC,eAAe,KAAK,kBAAkB,IAAI,eAAe,GAAG,CAAC,EAAE,CAAC;wBACjG,OAAO,GAAG,IAAI,CAAA;wBACd,SAAQ;oBACV,CAAC;oBACD,KAAK,MAAM,KAAK,IAAI,SAAS,CAAC,KAAK,EAAE,MAAM,EAAE,SAAS,IAAI,EAAE,EAAE,MAAM,CAAC,EAAE,CAAC;wBACtE,MAAM,YAAY,GAAG,CAAC,KAAK,CAAC,KAAK,GAAG,KAAK,CAAC,OAAO,CAAC,GAAG,IAAI,CAAA;wBACzD,MAAM,OAAO,GAAG,IAAI,CAAC,GAAG,CAAC,IAAI,EAAE,YAAY,CAAC,CAAA;wBAC5C,IAAI,IAAI,OAAO,CAAA;wBACf,MAAM,QAAQ,GAAG,IAAI,CAAC,GAAG,CAAC,YAAY,GAAG,OAAO,EAAE,eAAe,CAAC,CAAA;wBAClE,MAAM,SAAS,GAAG,IAAI,CAAC,GAAG,CAAC,SAAS,EAAE,QAAQ,CAAC,CAAA;wBAC/C,IAAI,SAAS,GAAG,CAAC,EAAE,CAAC;4BAClB,qFAAqF;4BACrF,oFAAoF;4BACpF,oCAAoC;4BACpC,IAAI,MAAM,KAAK,MAAM,IAAI,SAAS,GAAG,qBAAqB;gCAAE,SAAQ;4BACpE,QAAQ,CAAC,IAAI,CAAC;gCACZ,KAAK;gCACL,OAAO,EAAE,SAAS;gCAClB,SAAS,EAAE,IAAI,IAAI,CAAC,KAAK,CAAC,OAAO,GAAG,OAAO,GAAG,IAAI,CAAC;6BACpD,CAAC,CAAA;4BACF,SAAS,IAAI,SAAS,CAAA;4BACtB,eAAe,IAAI,SAAS,CAAA;wBAC9B,CAAC;oBACH,CAAC;gBACH,CAAC;gBACD,MAAM,iBAAiB,GAAG,QAAQ,CAAC,MAAM,CAAC,CAAC,GAAG,EAAE,OAAO,EAAE,EAAE,CAAC,GAAG,GAAG,OAAO,CAAC,OAAO,EAAE,CAAC,CAAC,CAAA;gBACrF,OAAO;oBACL,OAAO,EAAE,iBAAiB;oBAC1B,eAAe,EAAE,IAAI,CAAC,GAAG,CAAC,CAAC,EAAE,OAAO,GAAG,iBAAiB,CAAC;oBACzD,GAAG,CAAC,OAAO,IAAI,EAAE,OAAO,EAAE,kBAAkB,EAAE,CAAC;oBAC/C,QAAQ;oBACR,SAAS,EAAE,QAAQ,CAAC,CAAC,CAAC,EAAE,SAAS;iBAClC,CAAA;YACH,CAAC,CAAA;YACD,MAAM,QAAQ,GAAG,IAAI,CAAC,KAAK,CAAC,aAAa,EAAE,UAAU,CAAC,CAAA;YACtD,MAAM,IAAI,GAAG,IAAI,CAAC,KAAK,CAAC,SAAS,EAAE,MAAM,CAAC,CAAA;YAC1C,IAAI,QAAQ,CAAC,OAAO,KAAK,CAAC,IAAI,IAAI,CAAC,OAAO,KAAK,CAAC,IAAI,QAAQ,CAAC,OAAO,KAAK,SAAS,EAAE,CAAC;gBACnF,OAAO,EAAE,IAAI,EAAE,cAAc,EAAE,cAAc,EAAE,qBAAqB,EAAE,CAAA;YACxE,CAAC;YACD,OAAO;gBACL,IAAI,EAAE,OAAO;gBACb,SAAS;gBACT,GAAG,EAAE,QAAQ,CAAC,GAAG;gBACjB,OAAO;gBACP,QAAQ;gBACR,IAAI;aACL,CAAA;QACH,CAAC;KACF,CAAA;AACH,CAAC,CAAA;AAED;;;;;GAKG;AACH,MAAM,CAAC,MAAM,cAAc,GAAG,CAC5B,MAAoC,EACpC,MAAyC,EACC,EAAE;IAC5C,IAAI,MAAM,KAAK,SAAS;QAAE,OAAO,MAAM,CAAA;IACvC,MAAM,MAAM,GAAyB,EAAE,CAAA;IACvC,KAAK,MAAM,KAAK,IAAI,CAAC,GAAG,IAAI,GAAG,CAAC,MAAM,CAAC,CAAC,CAAC,IAAI,CAAC,CAAC,CAAC,EAAE,CAAC,EAAE,EAAE,CAAC,CAAC,GAAG,CAAC,CAAC,EAAE,CAAC;QAC/D,MAAM,KAAK,GAAG,MAAM,CAAC,KAAK,CAAC,CAAA;QAC3B,IAAI,KAAK,KAAK,SAAS;YAAE,OAAO,SAAS,CAAA;QACzC,MAAM,CAAC,IAAI,CAAC,KAAK,CAAC,CAAA;IACpB,CAAC;IACD,OAAO,MAAM,CAAC,MAAM,KAAK,CAAC,CAAC,CAAC,CAAC,SAAS,CAAC,CAAC,CAAC,MAAM,CAAA;AACjD,CAAC,CAAA;AA0BD;;GAEG;AACH,MAAM,CAAC,MAAM,qBAAqB,GAAG,EAAE,CAAA;AAEvC,MAAM,CAAC,MAAM,YAAY,GAAG,CAAC,OAY5B,EAAiB,EAAE;IAClB,MAAM,OAAO,GAAG,OAAO,CAAC,OAAO,IAAI,EAAE,QAAQ,EAAE,IAAI,EAAE,IAAI,EAAE,IAAI,EAAE,CAAA;IACjE,MAAM,QAAQ,GAAG,IAAI,CAAC,GAAG,CAAC,OAAO,CAAC,QAAQ,IAAI,OAAO,CAAC,QAAQ,EAAE,OAAO,CAAC,QAAQ,CAAC,CAAA;IACjF,MAAM,SAAS,GAAG,OAAO,CAAC,SAAS,IAAI,QAAQ,CAAA;IAC/C,IAAI,SAAS,GAAG,QAAQ;QAAE,OAAO,EAAE,IAAI,EAAE,cAAc,EAAE,UAAU,EAAE,QAAQ,EAAE,CAAA;IAC/E,IAAI,SAAS,GAAG,CAAC,OAAO,CAAC,QAAQ,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,qBAAqB,CAAC,EAAE,CAAC;QAC/D,OAAO,EAAE,IAAI,EAAE,cAAc,EAAE,cAAc,EAAE,OAAO,CAAC,QAAQ,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,qBAAqB,EAAE,CAAA;IAC/F,CAAC;IACD,MAAM,IAAI,GAAG,CAAC,IAAY,EAAE,YAAoB,EAAE,KAAc,EAAE,OAAe,EAAU,EAAE;QAC3F,IAAI,CAAC,KAAK;YAAE,OAAO,CAAC,CAAA;QACpB,uEAAuE;QACvE,MAAM,IAAI,GAAG,IAAI,CAAC,GAAG,CAAC,CAAC,EAAE,OAAO,CAAC,QAAQ,GAAG,IAAI,CAAC,CAAA;QACjD,MAAM,KAAK,GAAG,IAAI,CAAC,GAAG,CAAC,IAAI,CAAC,GAAG,CAAC,CAAC,EAAE,SAAS,GAAG,YAAY,CAAC,EAAE,IAAI,CAAC,CAAA;QACnE,OAAO,KAAK,GAAG,OAAO,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,KAAK,CAAA;IACpC,CAAC,CAAA;IACD,MAAM,aAAa,GAAG,IAAI,CACxB,OAAO,CAAC,mBAAmB,EAC3B,OAAO,CAAC,2BAA2B,IAAI,CAAC,EACxC,OAAO,CAAC,QAAQ,EAChB,CAAC,CACF,CAAA;IACD,MAAM,SAAS,GAAG,IAAI,CACpB,OAAO,CAAC,eAAe,EACvB,OAAO,CAAC,uBAAuB,IAAI,CAAC,EACpC,OAAO,CAAC,IAAI,EACZ,qBAAqB,CACtB,CAAA;IACD,iGAAiG;IACjG,oEAAoE;IACpE,IAAI,aAAa,KAAK,CAAC,IAAI,SAAS,KAAK,CAAC;QAAE,OAAO,EAAE,IAAI,EAAE,aAAa,EAAE,CAAA;IAC1E,OAAO,EAAE,IAAI,EAAE,OAAO,EAAE,aAAa,EAAE,SAAS,EAAE,CAAA;AACpD,CAAC,CAAA;AAED;;;;;;;;;;;;GAYG;AACH,MAAM,CAAC,MAAM,WAAW,GAAG,CACzB,KAAkC,EAClC,sBAA8B,EACZ,EAAE;IACpB,MAAM,OAAO,GAAG,CAAC,GAAG,KAAK,CAAC,CAAC,IAAI,CAAC,CAAC,CAAC,EAAE,CAAC,EAAE,EAAE,CAAC,CAAC,CAAC,OAAO,GAAG,CAAC,CAAC,OAAO,CAAC,CAAA;IAChE,IAAI,SAAS,GAAG,sBAAsB,CAAA;IACtC,KAAK,MAAM,IAAI,IAAI,OAAO,EAAE,CAAC;QAC3B,MAAM,OAAO,GAAG,CAAC,IAAI,CAAC,KAAK,GAAG,IAAI,CAAC,OAAO,CAAC,GAAG,IAAI,CAAA;QAClD,IAAI,SAAS,IAAI,OAAO,EAAE,CAAC;YACzB,SAAS,IAAI,OAAO,CAAA;YACpB,SAAQ;QACV,CAAC;QACD,OAAO,IAAI,IAAI,CAAC,IAAI,CAAC,OAAO,GAAG,SAAS,GAAG,IAAI,CAAC,CAAA;IAClD,CAAC;IACD,kGAAkG;IAClG,kGAAkG;IAClG,4EAA4E;IAC5E,MAAM,IAAI,GAAG,OAAO,CAAC,OAAO,CAAC,MAAM,GAAG,CAAC,CAAC,CAAA;IACxC,OAAO,IAAI,KAAK,SAAS,CAAC,CAAC,CAAC,SAAS,CAAC,CAAC,CAAC,IAAI,IAAI,CAAC,IAAI,CAAC,KAAK,CAAC,CAAA;AAC9D,CAAC,CAAA"}
@@ -0,0 +1,3 @@
1
+ #!/usr/bin/env node
2
+ export {};
3
+ //# sourceMappingURL=bin.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"bin.d.ts","sourceRoot":"","sources":["../../src/bin.ts"],"names":[],"mappings":""}
package/dist/src/bin.js CHANGED
@@ -6,11 +6,12 @@
6
6
  */
7
7
  import { NodeRuntime } from "@effect/platform-node";
8
8
  import { Effect } from "effect";
9
+ import { Command } from "effect/cli";
9
10
  import * as Runtime from "effect/Runtime";
10
11
  import * as Stdio from "effect/Stdio";
11
- import { Command } from "effect/unstable/cli";
12
12
  import { HeadlessLayer } from "./cli/layers.js";
13
13
  import { root } from "./cli/root.js";
14
+ import { reportUnhandled } from "./cli/runtimeFailure.js";
14
15
  const processArgv = Effect.gen(function* () {
15
16
  const stdio = yield* Stdio.Stdio;
16
17
  const args = yield* stdio.args;
@@ -19,7 +20,10 @@ const processArgv = Effect.gen(function* () {
19
20
  const cli = Command.runWith(root, {
20
21
  version: "0.1.0"
21
22
  });
22
- const program = processArgv.pipe(Effect.flatMap((argv) => cli(argv)), Effect.provide(HeadlessLayer));
23
+ const program = reportUnhandled(processArgv.pipe(Effect.flatMap((argv) => cli(argv)))).pipe(
24
+ // This *is* the entry point: the one place the whole layer graph is composed and provided.
25
+ // @effect-diagnostics-next-line strictEffectProvide:off
26
+ Effect.provide(HeadlessLayer));
23
27
  // The TUI keeps long-lived resources open through its atom runtime, and OpenTUI
24
28
  // holds stdin in raw mode so Ctrl-C arrives as a keypress, not a SIGINT. On a
25
29
  // clean in-app quit (exit code 0) runMain's default teardown never reaches
@@ -27,5 +31,7 @@ const program = processArgv.pipe(Effect.flatMap((argv) => cli(argv)), Effect.pro
27
31
  // UI tears down. This bin also runs as the Bun child re-spawned from the Node
28
32
  // parent, so both processes need the explicit exit. Always terminate.
29
33
  const forceExitTeardown = (exit) => Runtime.defaultTeardown(exit, (code) => process.exit(code));
30
- NodeRuntime.runMain(program, { teardown: forceExitTeardown });
34
+ // The command boundary above renders unreported failures once. Runtime reporting stays disabled so
35
+ // it cannot add a second stack trace after that concise diagnostic.
36
+ NodeRuntime.runMain(program, { disableErrorReporting: true, teardown: forceExitTeardown });
31
37
  //# sourceMappingURL=bin.js.map
@@ -1 +1 @@
1
- {"version":3,"file":"bin.js","sourceRoot":"","sources":["../../src/bin.ts"],"names":[],"mappings":";AACA;;;;GAIG;AACH,OAAO,EAAE,WAAW,EAAE,MAAM,uBAAuB,CAAA;AACnD,OAAO,EAAE,MAAM,EAAE,MAAM,QAAQ,CAAA;AAC/B,OAAO,KAAK,OAAO,MAAM,gBAAgB,CAAA;AACzC,OAAO,KAAK,KAAK,MAAM,cAAc,CAAA;AACrC,OAAO,EAAE,OAAO,EAAE,MAAM,qBAAqB,CAAA;AAC7C,OAAO,EAAE,aAAa,EAAE,MAAM,iBAAiB,CAAA;AAC/C,OAAO,EAAE,IAAI,EAAE,MAAM,eAAe,CAAA;AAEpC,MAAM,WAAW,GAAG,MAAM,CAAC,GAAG,CAAC,QAAQ,CAAC;IACtC,MAAM,KAAK,GAAG,KAAK,CAAC,CAAC,KAAK,CAAC,KAAK,CAAA;IAChC,MAAM,IAAI,GAAG,KAAK,CAAC,CAAC,KAAK,CAAC,IAAI,CAAA;IAC9B,OAAO,IAAI,CAAA;AACb,CAAC,CAAC,CAAA;AAEF,MAAM,GAAG,GAAG,OAAO,CAAC,OAAO,CAAC,IAAI,EAAE;IAChC,OAAO,EAAE,OAAO;CACjB,CAAC,CAAA;AAEF,MAAM,OAAO,GAAG,WAAW,CAAC,IAAI,CAC9B,MAAM,CAAC,OAAO,CAAC,CAAC,IAAI,EAAE,EAAE,CAAC,GAAG,CAAC,IAAI,CAAC,CAAC,EACnC,MAAM,CAAC,OAAO,CAAC,aAAa,CAAC,CAC9B,CAAA;AAED,gFAAgF;AAChF,8EAA8E;AAC9E,2EAA2E;AAC3E,8EAA8E;AAC9E,8EAA8E;AAC9E,sEAAsE;AACtE,MAAM,iBAAiB,GAAqB,CAAC,IAAI,EAAE,EAAE,CAAC,OAAO,CAAC,eAAe,CAAC,IAAI,EAAE,CAAC,IAAI,EAAE,EAAE,CAAC,OAAO,CAAC,IAAI,CAAC,IAAI,CAAC,CAAC,CAAA;AAEjH,WAAW,CAAC,OAAO,CAAC,OAAO,EAAE,EAAE,QAAQ,EAAE,iBAAiB,EAAE,CAAC,CAAA"}
1
+ {"version":3,"file":"bin.js","sourceRoot":"","sources":["../../src/bin.ts"],"names":[],"mappings":";AACA;;;;GAIG;AACH,OAAO,EAAE,WAAW,EAAE,MAAM,uBAAuB,CAAA;AACnD,OAAO,EAAE,MAAM,EAAE,MAAM,QAAQ,CAAA;AAC/B,OAAO,EAAE,OAAO,EAAE,MAAM,YAAY,CAAA;AACpC,OAAO,KAAK,OAAO,MAAM,gBAAgB,CAAA;AACzC,OAAO,KAAK,KAAK,MAAM,cAAc,CAAA;AACrC,OAAO,EAAE,aAAa,EAAE,MAAM,iBAAiB,CAAA;AAC/C,OAAO,EAAE,IAAI,EAAE,MAAM,eAAe,CAAA;AACpC,OAAO,EAAE,eAAe,EAAE,MAAM,yBAAyB,CAAA;AAEzD,MAAM,WAAW,GAAG,MAAM,CAAC,GAAG,CAAC,QAAQ,CAAC;IACtC,MAAM,KAAK,GAAG,KAAK,CAAC,CAAC,KAAK,CAAC,KAAK,CAAA;IAChC,MAAM,IAAI,GAAG,KAAK,CAAC,CAAC,KAAK,CAAC,IAAI,CAAA;IAC9B,OAAO,IAAI,CAAA;AACb,CAAC,CAAC,CAAA;AAEF,MAAM,GAAG,GAAG,OAAO,CAAC,OAAO,CAAC,IAAI,EAAE;IAChC,OAAO,EAAE,OAAO;CACjB,CAAC,CAAA;AAEF,MAAM,OAAO,GAAG,eAAe,CAAC,WAAW,CAAC,IAAI,CAC9C,MAAM,CAAC,OAAO,CAAC,CAAC,IAAI,EAAE,EAAE,CAAC,GAAG,CAAC,IAAI,CAAC,CAAC,CACpC,CAAC,CAAC,IAAI;AACL,2FAA2F;AAC3F,wDAAwD;AACxD,MAAM,CAAC,OAAO,CAAC,aAAa,CAAC,CAC9B,CAAA;AAED,gFAAgF;AAChF,8EAA8E;AAC9E,2EAA2E;AAC3E,8EAA8E;AAC9E,8EAA8E;AAC9E,sEAAsE;AACtE,MAAM,iBAAiB,GAAqB,CAAC,IAAI,EAAE,EAAE,CAAC,OAAO,CAAC,eAAe,CAAC,IAAI,EAAE,CAAC,IAAI,EAAE,EAAE,CAAC,OAAO,CAAC,IAAI,CAAC,IAAI,CAAC,CAAC,CAAA;AAEjH,mGAAmG;AACnG,oEAAoE;AACpE,WAAW,CAAC,OAAO,CAAC,OAAO,EAAE,EAAE,qBAAqB,EAAE,IAAI,EAAE,QAAQ,EAAE,iBAAiB,EAAE,CAAC,CAAA"}
@@ -0,0 +1,164 @@
1
+ /**
2
+ * Writing one Proposed Worklog, shared by `jcf sync reconcile --agent`, `jcf watch`, and any other
3
+ * surface that offers a proposal for confirmation.
4
+ *
5
+ * **Mental model**
6
+ *
7
+ * - **One write path**: every surface derives proposals from the same evidence and must put the same
8
+ * text in the same two places. A second implementation would drift, and the drift would only ever
9
+ * be visible in someone else's timesheet.
10
+ * - **Say it before writing it**: the entry text lands in two systems other people read, so the
11
+ * caller shows it first. Nothing here writes anything the user has not already been shown.
12
+ * - **Reports, never prints.** A write returns what each side did and the caller renders it. A
13
+ * terminal has a console to print to and an HTTP handler has a response to fill; a write path that
14
+ * printed could only ever serve the first, and the second would grow its own copy of these rules.
15
+ *
16
+ * @module
17
+ */
18
+ import * as Effect from "effect/Effect";
19
+ import type { SessionProposal } from "../agent/sessions.js";
20
+ import { type PlannedWrite, type WriteTargets } from "../agent/writePlanning.js";
21
+ import type { JiraAvailability, ProviderScopes, ReconcileServiceContract } from "../services/ReconcileService.js";
22
+ export { writeAnchor, type WriteTargets } from "../agent/writePlanning.js";
23
+ /** Clip `text` to `width`, marking that something was dropped. */
24
+ export declare const clip: (text: string, width: number) => string;
25
+ /**
26
+ * What accepting one row would write, naming only the sides that are actually short.
27
+ *
28
+ * Collapsed to "to both" when the two gaps are equal, which is the usual case for time neither
29
+ * side ever recorded — spelling the same number out twice reads like a mistake.
30
+ */
31
+ export declare const proposalTargets: (proposal: Pick<SessionProposal, "blocks" | "clockifyDelta" | "jiraDelta">) => string;
32
+ /**
33
+ * What a written entry claims about itself.
34
+ *
35
+ * The distinctions are not decoration. `session` evidence is the claim ADR-0006 lets the tool make —
36
+ * a transcript recorded that this work happened for this long. Every flag here is a place a person
37
+ * overruled that, and a row where they did must not keep citing evidence for the part they chose.
38
+ * Which is why this is three independent facts and not one label: an amount typed over a proposal
39
+ * still has a transcript behind *when* the work happened, and a proposal moved to another Issue Key
40
+ * still has a transcript behind *how long* it took.
41
+ */
42
+ export interface WriteProvenance {
43
+ /** `session` when a transcript stands behind the time; `hand` when nothing does. */
44
+ readonly evidence: "session" | "hand";
45
+ /** The amount was set by a person rather than taken from the evidence. */
46
+ readonly amountSetByHand: boolean;
47
+ /** The Issue Key was chosen by a person rather than by an Attribution Signal. */
48
+ readonly ticketSetByHand: boolean;
49
+ }
50
+ /** A proposal accepted exactly as it was offered. */
51
+ export declare const asProposed: WriteProvenance;
52
+ /** Time no session evidences: a meeting, a whiteboard, work away from the keyboard. */
53
+ export declare const byHand: WriteProvenance;
54
+ /**
55
+ * Where a written entry says it came from. This prose is never load-bearing: ordinary writes tally
56
+ * by `[KEY]` and day. Session-backed writes also carry a source suffix for legacy migration; the
57
+ * private provider-ID ledger, not editable text, keeps corrected-ticket consumption after a write.
58
+ */
59
+ export declare const PROVENANCE = "Reconciled from Claude Agent Session";
60
+ /** What an entry with this provenance says about itself. */
61
+ export declare const provenanceText: (provenance: WriteProvenance) => string;
62
+ /**
63
+ * What a written entry says about itself: the issue title, what was done, and where it came from.
64
+ *
65
+ * An entry that says only "reconciled from an Agent Session" answers the wrong question. The one
66
+ * asked of a timesheet months later is *what* the time went on, and by then the Issue Key alone is
67
+ * a lookup and the transcript is gone. So the title goes in — Clockify has no other way to know it —
68
+ * and the note goes in after it, as the one thing neither system can reconstruct.
69
+ *
70
+ * Both halves are optional, for different reasons: Jira may be unreachable, and a session whose
71
+ * prompts never say what was done gets no sentence rather than an invented one. The provenance stays
72
+ * last and unconditional — a reader has to be able to tell that a line was written by a tool from a
73
+ * session, not typed by hand.
74
+ */
75
+ export declare const entryDescription: (options: {
76
+ readonly summary: string | null;
77
+ readonly note: string | null;
78
+ /** Defaults to a proposal accepted as offered — the only kind the CLI's own commands write. */
79
+ readonly provenance?: WriteProvenance | undefined;
80
+ }) => string;
81
+ /**
82
+ * What one side of a write did.
83
+ *
84
+ * `NothingOwed` is not a failure and not a write: the side already holds the proposal's time, which
85
+ * is the ordinary outcome of topping up a day only one system missed. `Skipped` is a different
86
+ * statement again — the side was never asked. Keeping all three distinct from a `Written` of zero is
87
+ * what stops a summary counting any of them as work logged, and stops "you asked me not to" reading
88
+ * as "there was nothing to do".
89
+ */
90
+ export type SideOutcome = {
91
+ readonly _tag: "Written";
92
+ readonly seconds: number;
93
+ readonly segments?: ReadonlyArray<WrittenSegment>;
94
+ } | {
95
+ readonly _tag: "PartiallyWritten";
96
+ readonly seconds: number;
97
+ readonly segments?: ReadonlyArray<WrittenSegment>;
98
+ readonly failure: {
99
+ readonly _tag: "Refused";
100
+ readonly message: string;
101
+ } | {
102
+ readonly _tag: "NotLoggedIn";
103
+ };
104
+ } | {
105
+ readonly _tag: "NothingOwed";
106
+ } | {
107
+ readonly _tag: "Skipped";
108
+ } | {
109
+ readonly _tag: "Refused";
110
+ readonly message: string;
111
+ }
112
+ /** Jira only: the session expired, so every later Jira write would fail the same way. */
113
+ | {
114
+ readonly _tag: "NotLoggedIn";
115
+ };
116
+ export interface WrittenSegment {
117
+ readonly startMs: number;
118
+ readonly endMs: number;
119
+ }
120
+ /** Both systems: what a write means unless someone says otherwise. */
121
+ export declare const bothTargets: WriteTargets;
122
+ /**
123
+ * What one write attempt achieved, per side.
124
+ *
125
+ * Per side rather than a single boolean because the two fail independently, and a caller that
126
+ * summarises what it wrote must not count a side that refused.
127
+ */
128
+ export interface WriteOutcome {
129
+ readonly clockify: SideOutcome;
130
+ readonly jira: SideOutcome;
131
+ }
132
+ /** Why later rows would repeat the same Jira failure, or `null` when the next row remains useful. */
133
+ export declare const writeStopReason: (outcome: WriteOutcome) => string | null;
134
+ /** Seconds this write actually put on Clockify. */
135
+ export declare const clockifyWritten: (outcome: WriteOutcome) => number;
136
+ /** Seconds this write actually put on Jira. */
137
+ export declare const jiraWritten: (outcome: WriteOutcome) => number;
138
+ /**
139
+ * Whether a run should go on to the next row.
140
+ *
141
+ * False for an expired Jira session or an unverified Jira account: every remaining Jira write
142
+ * would fail the same way, and twenty rows that all fail is worse than stopping at the first. A
143
+ * Clockify refusal, or a Jira refusal about *this* row, says nothing about the next one.
144
+ */
145
+ export declare const keepGoing: (outcome: WriteOutcome) => boolean;
146
+ /**
147
+ * One line per side saying what happened, in the words every surface should use.
148
+ *
149
+ * Here rather than in each caller so a terminal and a browser cannot describe the same write
150
+ * differently. Silent about a side that owed nothing — a row where only Jira was short should not
151
+ * report a Clockify non-event.
152
+ */
153
+ export declare const writeOutcomeLines: (outcome: WriteOutcome) => ReadonlyArray<string>;
154
+ /**
155
+ * Execute concrete per-side amounts and starts without reinterpreting their evidence.
156
+ *
157
+ * The plan's targets narrow which systems are touched. A side left out is reported as `Skipped` and its gap
158
+ * is left exactly as it was — so asking for Jira alone today and both tomorrow writes the Clockify
159
+ * half tomorrow, rather than treating the skipped side as settled.
160
+ */
161
+ export declare const applyPlannedWrite: (service: Pick<ReconcileServiceContract, "applyToClockify" | "applyToJira">, plan: PlannedWrite, description: string, sourceRowId?: string, expectedScopes?: ProviderScopes, jiraAvailability?: JiraAvailability) => Effect.Effect<WriteOutcome, never, never>;
162
+ /** Execute CLI/watch proposals while preserving exact corrected-ticket source consumption. */
163
+ export declare const applyProposal: (service: Pick<ReconcileServiceContract, "applyToClockify" | "applyToJira">, proposal: SessionProposal, description: string, sourceScopes: ProviderScopes, targets?: WriteTargets, jiraAvailability?: JiraAvailability) => Effect.Effect<WriteOutcome>;
164
+ //# sourceMappingURL=agentWrite.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"agentWrite.d.ts","sourceRoot":"","sources":["../../../src/cli/agentWrite.ts"],"names":[],"mappings":"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"}