@knpkv/jira-clockify 1.2.1 → 1.3.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +9 -2
- package/dist/package.json +1 -1
- package/dist/src/cli/timer/status.js +110 -71
- package/dist/src/cli/timer/status.js.map +1 -1
- package/dist/tsconfig.tsbuildinfo +1 -1
- package/nvim/lua/jcf/state.lua +191 -13
- package/package.json +1 -1
package/README.md
CHANGED
|
@@ -77,6 +77,11 @@ jcf auth status # Show auth status for both services
|
|
|
77
77
|
## Neovim Plugin
|
|
78
78
|
|
|
79
79
|
Ships with a Lua plugin in `nvim/lua/jcf/`. Auto-detects Jira issue keys from branch names.
|
|
80
|
+
Periodic status polling requires util-linux `flock`; the lock stays attached to
|
|
81
|
+
the `jcf` process so closing or killing Neovim cannot start an overlapping poll.
|
|
82
|
+
Polling always coordinates through fixed `~/.jcf/poll.lock` and
|
|
83
|
+
`~/.jcf/poll.stamp` files beside the CLI-owned `state.json`; a configured
|
|
84
|
+
`state_path` changes display reads only.
|
|
80
85
|
|
|
81
86
|
### lazy.nvim
|
|
82
87
|
|
|
@@ -88,7 +93,7 @@ Ships with a Lua plugin in `nvim/lua/jcf/`. Auto-detects Jira issue keys from br
|
|
|
88
93
|
binary = "jcf", -- path to jcf binary
|
|
89
94
|
auto_detect_branch = true, -- detect issue key from git branch
|
|
90
95
|
float = { width = 0.8, height = 0.8 },
|
|
91
|
-
poll_interval = 30000, --
|
|
96
|
+
poll_interval = 30000, -- positive integer ms; invalid/non-positive disables polling
|
|
92
97
|
})
|
|
93
98
|
end,
|
|
94
99
|
}
|
|
@@ -114,7 +119,9 @@ Stored in `~/.jcf/`:
|
|
|
114
119
|
~/.jcf/
|
|
115
120
|
├── config.json # JQL, project, billable defaults
|
|
116
121
|
├── clockify.json # Clockify API key, workspace, user
|
|
117
|
-
|
|
122
|
+
├── poll.lock # Kernel lock held by the active managed poll
|
|
123
|
+
├── poll.stamp # Last managed poll attempt, including failures
|
|
124
|
+
└── state.json # Current timer state and polling authority
|
|
118
125
|
```
|
|
119
126
|
|
|
120
127
|
Jira OAuth credentials stored via `@knpkv/atlassian-common` in `~/.config/atlassian/`.
|
package/dist/package.json
CHANGED
|
@@ -4,8 +4,8 @@
|
|
|
4
4
|
* @module
|
|
5
5
|
*/
|
|
6
6
|
import { ClockifyApiClient } from "@knpkv/clockify-api-client";
|
|
7
|
-
import { Clock, Console, Effect } from "effect";
|
|
8
|
-
import { Command } from "effect/unstable/cli";
|
|
7
|
+
import { Clock, Console, Data, Effect, FileSystem, Option, Schema } from "effect";
|
|
8
|
+
import { Command, Flag as Options } from "effect/unstable/cli";
|
|
9
9
|
import { ClockifyAuth } from "../../services/ClockifyAuth.js";
|
|
10
10
|
import { StateWriter } from "../../services/StateWriter.js";
|
|
11
11
|
/**
|
|
@@ -15,80 +15,119 @@ import { StateWriter } from "../../services/StateWriter.js";
|
|
|
15
15
|
* timer, so hung processes accumulate rather than being noticed. Bound them.
|
|
16
16
|
*/
|
|
17
17
|
const API_TIMEOUT = "10 seconds";
|
|
18
|
-
|
|
19
|
-
const
|
|
20
|
-
|
|
18
|
+
const pollTimestamp = (content) => {
|
|
19
|
+
const value = Number(content.trim());
|
|
20
|
+
return Number.isSafeInteger(value) && value >= 0 ? value : null;
|
|
21
|
+
};
|
|
22
|
+
const NvimPollGate = Data.taggedEnum();
|
|
23
|
+
const unmanagedPoll = NvimPollGate.Unmanaged();
|
|
24
|
+
const skipPoll = NvimPollGate.Skip();
|
|
25
|
+
const runPoll = (complete) => NvimPollGate.Run({ complete });
|
|
26
|
+
class InvalidNvimPollGate extends Schema.TaggedError()("InvalidNvimPollGate", { message: Schema.String }) {
|
|
27
|
+
}
|
|
28
|
+
const resolveNvimPollGate = Effect.fn("TimerStatus.resolveNvimPollGate")(function* (stampPath, intervalMs) {
|
|
29
|
+
if (Option.isNone(stampPath) && Option.isNone(intervalMs)) {
|
|
30
|
+
return unmanagedPoll;
|
|
31
|
+
}
|
|
32
|
+
if (Option.isNone(stampPath) || Option.isNone(intervalMs) || intervalMs.value <= 0) {
|
|
33
|
+
return yield* new InvalidNvimPollGate({
|
|
34
|
+
message: "nvim poll stamp and positive interval must be provided together"
|
|
35
|
+
});
|
|
36
|
+
}
|
|
37
|
+
const fs = yield* FileSystem.FileSystem;
|
|
21
38
|
const nowMs = yield* Clock.currentTimeMillis;
|
|
22
|
-
const
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
const auth = yield* clockifyAuth.getConfig.pipe(Effect.catch(() => Effect.succeed(null)));
|
|
28
|
-
if (auth) {
|
|
29
|
-
let apiReachable = false;
|
|
30
|
-
// The bound goes innermost: `apiReachable` gates clearing the state
|
|
31
|
-
// file, so the tap must only be reachable on an answer that actually
|
|
32
|
-
// won its race. Timing out around the tap would let the flag be set
|
|
33
|
-
// by a call the timeout then discards, and the `null` result would
|
|
34
|
-
// read as "API confirmed no timer" — clearing a live timer.
|
|
35
|
-
const running = yield* clockifyClient.getRunningTimer(auth.workspaceId, auth.userId).pipe(Effect.timeout(API_TIMEOUT), Effect.tap(() => Effect.sync(() => {
|
|
36
|
-
apiReachable = true;
|
|
37
|
-
})), Effect.catch(() => Effect.succeed(null)));
|
|
38
|
-
// Only clear if API was reachable and confirmed no running timer
|
|
39
|
-
if (apiReachable && !running) {
|
|
40
|
-
yield* stateWriter.clear;
|
|
41
|
-
yield* Console.log("Timer was stopped externally. State cleared.");
|
|
42
|
-
return;
|
|
43
|
-
}
|
|
44
|
-
// If timer still running, update state file (refreshes mtime for Lua statusline)
|
|
45
|
-
if (running) {
|
|
46
|
-
yield* stateWriter.write({
|
|
47
|
-
...state,
|
|
48
|
-
elapsed: state.startedAt_unix ? nowUnix - state.startedAt_unix : 0
|
|
49
|
-
});
|
|
50
|
-
}
|
|
39
|
+
const lastPoll = yield* fs.readFileString(stampPath.value).pipe(Effect.map(pollTimestamp), Effect.catchIf((error) => error.reason._tag === "NotFound", () => Effect.succeed(null)));
|
|
40
|
+
if (lastPoll !== null) {
|
|
41
|
+
const ageMs = nowMs - lastPoll;
|
|
42
|
+
if (ageMs >= 0 && ageMs < intervalMs.value) {
|
|
43
|
+
return skipPoll;
|
|
51
44
|
}
|
|
52
45
|
}
|
|
53
|
-
|
|
54
|
-
|
|
55
|
-
|
|
56
|
-
|
|
57
|
-
|
|
58
|
-
|
|
59
|
-
|
|
60
|
-
const
|
|
61
|
-
|
|
62
|
-
|
|
63
|
-
|
|
64
|
-
|
|
65
|
-
|
|
66
|
-
|
|
67
|
-
|
|
68
|
-
|
|
69
|
-
|
|
70
|
-
|
|
71
|
-
|
|
72
|
-
|
|
73
|
-
|
|
74
|
-
|
|
75
|
-
|
|
76
|
-
|
|
46
|
+
return runPoll(Clock.currentTimeMillis.pipe(Effect.flatMap((completedAt) => fs.writeFileString(stampPath.value, String(completedAt)))));
|
|
47
|
+
});
|
|
48
|
+
export const statusCmd = Command.make("status", {
|
|
49
|
+
nvimPollStamp: Options.string("nvim-poll-stamp").pipe(Options.withHidden, Options.optional),
|
|
50
|
+
nvimPollIntervalMs: Options.integer("nvim-poll-interval-ms").pipe(Options.withHidden, Options.optional)
|
|
51
|
+
}, ({ nvimPollIntervalMs, nvimPollStamp }) => Effect.gen(function* () {
|
|
52
|
+
const pollGate = yield* resolveNvimPollGate(nvimPollStamp, nvimPollIntervalMs);
|
|
53
|
+
const status = Effect.gen(function* () {
|
|
54
|
+
const stateWriter = yield* StateWriter;
|
|
55
|
+
const state = yield* stateWriter.read;
|
|
56
|
+
const nowMs = yield* Clock.currentTimeMillis;
|
|
57
|
+
const nowUnix = Math.floor(nowMs / 1000);
|
|
58
|
+
// Verify against Clockify — timer may have been stopped externally
|
|
59
|
+
if (state.active) {
|
|
60
|
+
const clockifyAuth = yield* ClockifyAuth;
|
|
61
|
+
const clockifyClient = yield* ClockifyApiClient;
|
|
62
|
+
const auth = yield* clockifyAuth.getConfig.pipe(Effect.catch(() => Effect.succeed(null)));
|
|
63
|
+
if (auth !== null) {
|
|
64
|
+
let apiReachable = false;
|
|
65
|
+
// The bound goes innermost: `apiReachable` gates clearing the state
|
|
66
|
+
// file, so the tap must only be reachable on an answer that actually
|
|
67
|
+
// won its race. Timing out around the tap would let the flag be set
|
|
68
|
+
// by a call the timeout then discards, and the `null` result would
|
|
69
|
+
// read as "API confirmed no timer" — clearing a live timer.
|
|
70
|
+
const running = yield* clockifyClient.getRunningTimer(auth.workspaceId, auth.userId).pipe(Effect.timeout(API_TIMEOUT), Effect.tap(() => Effect.sync(() => {
|
|
71
|
+
apiReachable = true;
|
|
72
|
+
})), Effect.catch(() => Effect.succeed(null)));
|
|
73
|
+
// Only clear if API was reachable and confirmed no running timer
|
|
74
|
+
if (apiReachable && running === null) {
|
|
75
|
+
yield* stateWriter.clear;
|
|
76
|
+
yield* Console.log("Timer was stopped externally. State cleared.");
|
|
77
|
+
return;
|
|
78
|
+
}
|
|
79
|
+
// If timer still running, update state file (refreshes mtime for Lua statusline)
|
|
80
|
+
if (running !== null) {
|
|
81
|
+
yield* stateWriter.write({
|
|
82
|
+
...state,
|
|
83
|
+
elapsed: state.startedAt_unix === null ? 0 : nowUnix - state.startedAt_unix
|
|
84
|
+
});
|
|
85
|
+
}
|
|
77
86
|
}
|
|
78
|
-
|
|
79
|
-
|
|
80
|
-
|
|
81
|
-
|
|
82
|
-
|
|
83
|
-
|
|
84
|
-
|
|
85
|
-
|
|
86
|
-
|
|
87
|
-
|
|
88
|
-
|
|
89
|
-
|
|
87
|
+
}
|
|
88
|
+
if (!state.active) {
|
|
89
|
+
yield* Console.log("No active timer");
|
|
90
|
+
return;
|
|
91
|
+
}
|
|
92
|
+
const elapsed = state.startedAt_unix === null ? 0 : nowUnix - state.startedAt_unix;
|
|
93
|
+
const h = Math.floor(elapsed / 3600);
|
|
94
|
+
const m = Math.floor((elapsed % 3600) / 60);
|
|
95
|
+
const s = elapsed % 60;
|
|
96
|
+
yield* Console.log(`● ${state.ticketKey} ${state.summary ?? ""}`);
|
|
97
|
+
yield* Console.log(` Time: ${String(h).padStart(2, "0")}:${String(m).padStart(2, "0")}:${String(s).padStart(2, "0")}`);
|
|
98
|
+
yield* Console.log(` Started: ${state.startedAt ?? "?"}`);
|
|
99
|
+
// Show project/billable from Clockify entry
|
|
100
|
+
const clockifyAuth = yield* ClockifyAuth;
|
|
101
|
+
const clockifyClient = yield* ClockifyApiClient;
|
|
102
|
+
const auth = yield* clockifyAuth.getConfig.pipe(Effect.catch(() => Effect.succeed(null)));
|
|
103
|
+
if (auth !== null && state.clockifyEntryId !== null) {
|
|
104
|
+
const entry = yield* clockifyClient.getTimeEntry(auth.workspaceId, state.clockifyEntryId).pipe(Effect.timeout(API_TIMEOUT), Effect.catch(() => Effect.succeed(null)));
|
|
105
|
+
if (entry !== null) {
|
|
106
|
+
let projectName = "none";
|
|
107
|
+
if (entry.projectId !== null && entry.projectId !== undefined) {
|
|
108
|
+
const projects = yield* clockifyClient.getProjects(auth.workspaceId).pipe(Effect.timeout(API_TIMEOUT), Effect.catch(() => Effect.succeed([])));
|
|
109
|
+
projectName = projects.find((p) => p.id === entry.projectId)?.name ?? entry.projectId;
|
|
110
|
+
}
|
|
111
|
+
yield* Console.log(` Project: ${projectName}`);
|
|
112
|
+
yield* Console.log(` Billable: ${entry.billable === true ? "yes" : "no"}`);
|
|
113
|
+
// Show tags
|
|
114
|
+
if (entry.tagIds !== null && entry.tagIds !== undefined && entry.tagIds.length > 0) {
|
|
115
|
+
const allTags = yield* clockifyClient.getTags(auth.workspaceId).pipe(Effect.timeout(API_TIMEOUT), Effect.catch(() => Effect.succeed([])));
|
|
116
|
+
const tagNames = entry.tagIds
|
|
117
|
+
.map((id) => allTags.find((t) => t.id === id)?.name ?? id)
|
|
118
|
+
.join(", ");
|
|
119
|
+
yield* Console.log(` Tags: ${tagNames}`);
|
|
120
|
+
}
|
|
121
|
+
else {
|
|
122
|
+
yield* Console.log(" Tags: none");
|
|
123
|
+
}
|
|
90
124
|
}
|
|
91
125
|
}
|
|
92
|
-
}
|
|
126
|
+
});
|
|
127
|
+
return yield* NvimPollGate.$match(pollGate, {
|
|
128
|
+
Unmanaged: () => status,
|
|
129
|
+
Skip: () => Effect.void,
|
|
130
|
+
Run: ({ complete }) => status.pipe(Effect.onExit(() => complete))
|
|
131
|
+
});
|
|
93
132
|
}));
|
|
94
133
|
//# sourceMappingURL=status.js.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"status.js","sourceRoot":"","sources":["../../../../src/cli/timer/status.ts"],"names":[],"mappings":"AAAA;;;;GAIG;AACH,OAAO,EAAE,iBAAiB,EAAE,MAAM,4BAA4B,CAAA;AAC9D,OAAO,EAAE,KAAK,EAAE,OAAO,EAAE,MAAM,EAAE,MAAM,QAAQ,CAAA;
|
|
1
|
+
{"version":3,"file":"status.js","sourceRoot":"","sources":["../../../../src/cli/timer/status.ts"],"names":[],"mappings":"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"}
|