@knpkv/jira-clockify 1.0.1 → 1.1.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (66) hide show
  1. package/dist/package.json +6 -6
  2. package/dist/src/cli/auth.js +22 -7
  3. package/dist/src/cli/auth.js.map +1 -1
  4. package/dist/src/cli/config.js.map +1 -1
  5. package/dist/src/cli/fetchTicket.js +9 -4
  6. package/dist/src/cli/fetchTicket.js.map +1 -1
  7. package/dist/src/cli/fuzzySelect.js.map +1 -1
  8. package/dist/src/cli/layers.js.map +1 -1
  9. package/dist/src/cli/setup.js +39 -9
  10. package/dist/src/cli/setup.js.map +1 -1
  11. package/dist/src/cli/timer/edit.js +14 -7
  12. package/dist/src/cli/timer/edit.js.map +1 -1
  13. package/dist/src/cli/timer/start.js +15 -10
  14. package/dist/src/cli/timer/start.js.map +1 -1
  15. package/dist/src/cli/timer/status.js +5 -3
  16. package/dist/src/cli/timer/status.js.map +1 -1
  17. package/dist/src/cli/timer/stop.js +51 -10
  18. package/dist/src/cli/timer/stop.js.map +1 -1
  19. package/dist/src/services/ClockifyAuth.js +2 -1
  20. package/dist/src/services/ClockifyAuth.js.map +1 -1
  21. package/dist/src/services/ConfigService.js +34 -1
  22. package/dist/src/services/ConfigService.js.map +1 -1
  23. package/dist/src/services/ReconcileService.js +0 -0
  24. package/dist/src/services/ReconcileService.js.map +1 -1
  25. package/dist/src/services/StateWriter.js +25 -1
  26. package/dist/src/services/StateWriter.js.map +1 -1
  27. package/dist/src/services/TicketService.js +13 -6
  28. package/dist/src/services/TicketService.js.map +1 -1
  29. package/dist/src/services/TimerService.js +45 -13
  30. package/dist/src/services/TimerService.js.map +1 -1
  31. package/dist/src/tui/App.js +69 -9
  32. package/dist/src/tui/App.js.map +1 -1
  33. package/dist/src/tui/components/BigTimer.js +1 -1
  34. package/dist/src/tui/components/BigTimer.js.map +1 -1
  35. package/dist/src/tui/components/Footer.js +11 -2
  36. package/dist/src/tui/components/Footer.js.map +1 -1
  37. package/dist/src/tui/components/Header.js +2 -1
  38. package/dist/src/tui/components/Header.js.map +1 -1
  39. package/dist/src/tui/components/PopupInput.js +10 -5
  40. package/dist/src/tui/components/PopupInput.js.map +1 -1
  41. package/dist/src/tui/components/PopupMessage.js +7 -3
  42. package/dist/src/tui/components/PopupMessage.js.map +1 -1
  43. package/dist/src/tui/components/TicketList.js +7 -8
  44. package/dist/src/tui/components/TicketList.js.map +1 -1
  45. package/dist/src/tui/components/TicketRow.js +7 -6
  46. package/dist/src/tui/components/TicketRow.js.map +1 -1
  47. package/dist/src/tui/components/TimerDisplay.js +1 -1
  48. package/dist/src/tui/components/TimerDisplay.js.map +1 -1
  49. package/dist/src/tui/hooks/useTerminalSize.js +3 -1
  50. package/dist/src/tui/hooks/useTerminalSize.js.map +1 -1
  51. package/dist/src/utils/time.js +72 -0
  52. package/dist/src/utils/time.js.map +1 -1
  53. package/dist/tsconfig.tsbuildinfo +1 -1
  54. package/package.json +9 -9
  55. package/dist/test/ReconcileService.test.js +0 -146
  56. package/dist/test/ReconcileService.test.js.map +0 -1
  57. package/dist/test/TimerService.test.js +0 -597
  58. package/dist/test/TimerService.test.js.map +0 -1
  59. package/dist/test/commandSurface.test.js +0 -42
  60. package/dist/test/commandSurface.test.js.map +0 -1
  61. package/dist/test/fetchTicket.test.js +0 -89
  62. package/dist/test/fetchTicket.test.js.map +0 -1
  63. package/dist/test/stopPrompts.test.js +0 -93
  64. package/dist/test/stopPrompts.test.js.map +0 -1
  65. package/dist/test/time.test.js +0 -84
  66. package/dist/test/time.test.js.map +0 -1
@@ -1,42 +0,0 @@
1
- import { describe, expect, it } from "@effect/vitest";
2
- import * as Effect from "effect/Effect";
3
- import { Command } from "effect/unstable/cli";
4
- import { HeadlessLayer } from "../src/cli/layers.js";
5
- import { root } from "../src/cli/root.js";
6
- const run = (args) => Command.runWith(root, { version: "0.0.0-test" })(args).pipe(Effect.provide(HeadlessLayer), Effect.exit);
7
- describe("jcf command surface", () => {
8
- const canonicalCommands = [
9
- ["timer"],
10
- ["timer", "start", "--help"],
11
- ["timer", "stop", "--help"],
12
- ["timer", "discard", "--help"],
13
- ["timer", "status", "--help"],
14
- ["timer", "log", "--help"],
15
- ["timer", "edit", "--help"],
16
- ["issue", "list", "--help"],
17
- ["sync", "reconcile", "--help"]
18
- ];
19
- for (const args of canonicalCommands) {
20
- it.effect(`accepts canonical command: jcf ${args.join(" ")}`, () => Effect.gen(function* () {
21
- const exit = yield* run(args);
22
- expect(exit._tag).toBe("Success");
23
- }));
24
- }
25
- const legacyCommands = [
26
- ["start"],
27
- ["stop"],
28
- ["discard"],
29
- ["status"],
30
- ["log"],
31
- ["edit"],
32
- ["list"],
33
- ["reconcile"]
34
- ];
35
- for (const args of legacyCommands) {
36
- it.effect(`rejects removed legacy command: jcf ${args.join(" ")}`, () => Effect.gen(function* () {
37
- const exit = yield* run(args);
38
- expect(exit._tag).toBe("Failure");
39
- }));
40
- }
41
- });
42
- //# sourceMappingURL=commandSurface.test.js.map
@@ -1 +0,0 @@
1
- {"version":3,"file":"commandSurface.test.js","sourceRoot":"","sources":["../../test/commandSurface.test.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,QAAQ,EAAE,MAAM,EAAE,EAAE,EAAE,MAAM,gBAAgB,CAAA;AACrD,OAAO,KAAK,MAAM,MAAM,eAAe,CAAA;AACvC,OAAO,EAAE,OAAO,EAAE,MAAM,qBAAqB,CAAA;AAC7C,OAAO,EAAE,aAAa,EAAE,MAAM,sBAAsB,CAAA;AACpD,OAAO,EAAE,IAAI,EAAE,MAAM,oBAAoB,CAAA;AAEzC,MAAM,GAAG,GAAG,CAAC,IAA2B,EAAE,EAAE,CAC1C,OAAO,CAAC,OAAO,CAAC,IAAI,EAAE,EAAE,OAAO,EAAE,YAAY,EAAE,CAAC,CAAC,IAAI,CAAC,CAAC,IAAI,CACzD,MAAM,CAAC,OAAO,CAAC,aAAa,CAAC,EAC7B,MAAM,CAAC,IAAI,CACZ,CAAA;AAEH,QAAQ,CAAC,qBAAqB,EAAE,GAAG,EAAE;IACnC,MAAM,iBAAiB,GAAG;QACxB,CAAC,OAAO,CAAC;QACT,CAAC,OAAO,EAAE,OAAO,EAAE,QAAQ,CAAC;QAC5B,CAAC,OAAO,EAAE,MAAM,EAAE,QAAQ,CAAC;QAC3B,CAAC,OAAO,EAAE,SAAS,EAAE,QAAQ,CAAC;QAC9B,CAAC,OAAO,EAAE,QAAQ,EAAE,QAAQ,CAAC;QAC7B,CAAC,OAAO,EAAE,KAAK,EAAE,QAAQ,CAAC;QAC1B,CAAC,OAAO,EAAE,MAAM,EAAE,QAAQ,CAAC;QAC3B,CAAC,OAAO,EAAE,MAAM,EAAE,QAAQ,CAAC;QAC3B,CAAC,MAAM,EAAE,WAAW,EAAE,QAAQ,CAAC;KACvB,CAAA;IAEV,KAAK,MAAM,IAAI,IAAI,iBAAiB,EAAE,CAAC;QACrC,EAAE,CAAC,MAAM,CAAC,kCAAkC,IAAI,CAAC,IAAI,CAAC,GAAG,CAAC,EAAE,EAAE,GAAG,EAAE,CACjE,MAAM,CAAC,GAAG,CAAC,QAAQ,CAAC;YAClB,MAAM,IAAI,GAAG,KAAK,CAAC,CAAC,GAAG,CAAC,IAAI,CAAC,CAAA;YAE7B,MAAM,CAAC,IAAI,CAAC,IAAI,CAAC,CAAC,IAAI,CAAC,SAAS,CAAC,CAAA;QACnC,CAAC,CAAC,CAAC,CAAA;IACP,CAAC;IAED,MAAM,cAAc,GAAG;QACrB,CAAC,OAAO,CAAC;QACT,CAAC,MAAM,CAAC;QACR,CAAC,SAAS,CAAC;QACX,CAAC,QAAQ,CAAC;QACV,CAAC,KAAK,CAAC;QACP,CAAC,MAAM,CAAC;QACR,CAAC,MAAM,CAAC;QACR,CAAC,WAAW,CAAC;KACL,CAAA;IAEV,KAAK,MAAM,IAAI,IAAI,cAAc,EAAE,CAAC;QAClC,EAAE,CAAC,MAAM,CAAC,uCAAuC,IAAI,CAAC,IAAI,CAAC,GAAG,CAAC,EAAE,EAAE,GAAG,EAAE,CACtE,MAAM,CAAC,GAAG,CAAC,QAAQ,CAAC;YAClB,MAAM,IAAI,GAAG,KAAK,CAAC,CAAC,GAAG,CAAC,IAAI,CAAC,CAAA;YAE7B,MAAM,CAAC,IAAI,CAAC,IAAI,CAAC,CAAC,IAAI,CAAC,SAAS,CAAC,CAAA;QACnC,CAAC,CAAC,CAAC,CAAA;IACP,CAAC;AACH,CAAC,CAAC,CAAA"}
@@ -1,89 +0,0 @@
1
- import { describe, expect, it } from "@effect/vitest";
2
- import { JiraApiClient } from "@knpkv/jira-api-client";
3
- import { JiraAuth } from "@knpkv/jira-cli/JiraAuth";
4
- import * as Effect from "effect/Effect";
5
- import * as Layer from "effect/Layer";
6
- import { fetchTicketByKey } from "../src/cli/fetchTicket.js";
7
- // ---------------------------------------------------------------------------
8
- // Helpers
9
- // ---------------------------------------------------------------------------
10
- /**
11
- * Build a JiraApiClient mock whose `v3.client.GET` resolves the openapi-fetch
12
- * `{ data, error, response }` shape that `toEffect` consumes.
13
- */
14
- const makeJiraLayer = (resolve) => Layer.succeed(JiraApiClient, {
15
- v3: {
16
- client: {
17
- GET: () => Promise.resolve(resolve())
18
- }
19
- }
20
- });
21
- // JiraAuth mock — only `isLoggedIn` matters for fetchTicketByKey.
22
- const makeAuthLayer = (loggedIn) => Layer.succeed(JiraAuth, {
23
- isLoggedIn: () => Effect.succeed(loggedIn)
24
- });
25
- // JiraAuth whose isLoggedIn fails with a platform error (e.g. unreadable token file).
26
- const makeAuthFailLayer = (message) => Layer.succeed(JiraAuth, {
27
- isLoggedIn: () => Effect.fail({ message })
28
- });
29
- const LoggedIn = makeAuthLayer(true);
30
- const issueFixture = {
31
- key: "PROJ-7",
32
- fields: {
33
- summary: "Wire up the thing",
34
- status: { name: "In Progress" },
35
- priority: { name: "High" },
36
- assignee: { displayName: "Dev" },
37
- issuetype: { name: "Story" },
38
- labels: ["backend", "api"],
39
- updated: "2025-06-01T10:00:00.000Z"
40
- }
41
- };
42
- // ---------------------------------------------------------------------------
43
- // Tests
44
- // ---------------------------------------------------------------------------
45
- describe("fetchTicketByKey", () => {
46
- // Happy path: the issue is shaped through the shared mapper into a JiraTicket
47
- it.effect("returns Found with a fully-mapped ticket", () => Effect.gen(function* () {
48
- const result = yield* fetchTicketByKey("PROJ-7");
49
- expect(result._tag).toBe("Found");
50
- if (result._tag !== "Found")
51
- return;
52
- expect(result.ticket.key).toBe("PROJ-7");
53
- expect(result.ticket.summary).toBe("Wire up the thing");
54
- expect(result.ticket.status).toBe("In Progress");
55
- expect(result.ticket.priority).toBe("High");
56
- expect(result.ticket.assignee).toBe("Dev");
57
- expect(result.ticket.type).toBe("Story");
58
- expect(result.ticket.labels).toEqual(["backend", "api"]);
59
- }).pipe(Effect.provide(makeJiraLayer(() => ({ data: issueFixture, response: { ok: true, status: 200 } }))), Effect.provide(LoggedIn)));
60
- // A 404 must map to NotFound (genuine "no such issue")
61
- it.effect("returns NotFound on a 404", () => Effect.gen(function* () {
62
- const result = yield* fetchTicketByKey("PROJ-404");
63
- expect(result._tag).toBe("NotFound");
64
- }).pipe(Effect.provide(makeJiraLayer(() => ({ error: { errorMessages: ["not found"] }, response: { ok: false, status: 404 } }))), Effect.provide(LoggedIn)));
65
- // A non-404 failure (auth/network) must map to FetchError, NOT NotFound —
66
- // so a 401 is never reported to the user as "Ticket not found".
67
- it.effect("returns FetchError on a 401 (distinct from NotFound)", () => Effect.gen(function* () {
68
- const result = yield* fetchTicketByKey("PROJ-1");
69
- expect(result._tag).toBe("FetchError");
70
- }).pipe(Effect.provide(makeJiraLayer(() => ({ error: { errorMessages: ["unauthorized"] }, response: { ok: false, status: 401 } }))), Effect.provide(LoggedIn)));
71
- // Not logged in must short-circuit to NotLoggedIn — an unauthenticated request
72
- // 404s on a malformed URL and would otherwise masquerade as "ticket not found".
73
- it.effect("returns NotLoggedIn when not authenticated", () => Effect.gen(function* () {
74
- const result = yield* fetchTicketByKey("PROJ-7");
75
- expect(result._tag).toBe("NotLoggedIn");
76
- }).pipe(
77
- // The Jira client would succeed, but the login check must short-circuit first.
78
- Effect.provide(makeJiraLayer(() => ({ data: issueFixture, response: { ok: true, status: 200 } }))), Effect.provide(makeAuthLayer(false))));
79
- // A genuine platform error reading the token must NOT masquerade as NotLoggedIn —
80
- // it is a real failure and should route to FetchError (only a clean absent token is NotLoggedIn).
81
- it.effect("returns FetchError when the login check fails with a platform error", () => Effect.gen(function* () {
82
- const result = yield* fetchTicketByKey("PROJ-7");
83
- expect(result._tag).toBe("FetchError");
84
- if (result._tag !== "FetchError")
85
- return;
86
- expect(result.message).toBe("token file unreadable");
87
- }).pipe(Effect.provide(makeJiraLayer(() => ({ data: issueFixture, response: { ok: true, status: 200 } }))), Effect.provide(makeAuthFailLayer("token file unreadable"))));
88
- });
89
- //# sourceMappingURL=fetchTicket.test.js.map
@@ -1 +0,0 @@
1
- {"version":3,"file":"fetchTicket.test.js","sourceRoot":"","sources":["../../test/fetchTicket.test.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,QAAQ,EAAE,MAAM,EAAE,EAAE,EAAE,MAAM,gBAAgB,CAAA;AACrD,OAAO,EAAE,aAAa,EAAE,MAAM,wBAAwB,CAAA;AACtD,OAAO,EAAE,QAAQ,EAAE,MAAM,0BAA0B,CAAA;AACnD,OAAO,KAAK,MAAM,MAAM,eAAe,CAAA;AACvC,OAAO,KAAK,KAAK,MAAM,cAAc,CAAA;AACrC,OAAO,EAAE,gBAAgB,EAAE,MAAM,2BAA2B,CAAA;AAE5D,8EAA8E;AAC9E,UAAU;AACV,8EAA8E;AAE9E;;;GAGG;AACH,MAAM,aAAa,GAAG,CACpB,OAA6F,EAC7F,EAAE,CACF,KAAK,CAAC,OAAO,CAAC,aAAa,EAAE;IAC3B,EAAE,EAAE;QACF,MAAM,EAAE;YACN,GAAG,EAAE,GAAG,EAAE,CAAC,OAAO,CAAC,OAAO,CAAC,OAAO,EAAE,CAAC;SACtC;KACF;CACO,CAAC,CAAA;AAEb,kEAAkE;AAClE,MAAM,aAAa,GAAG,CAAC,QAAiB,EAAE,EAAE,CAC1C,KAAK,CAAC,OAAO,CAAC,QAAQ,EAAE;IACtB,UAAU,EAAE,GAAG,EAAE,CAAC,MAAM,CAAC,OAAO,CAAC,QAAQ,CAAC;CAClC,CAAC,CAAA;AAEb,sFAAsF;AACtF,MAAM,iBAAiB,GAAG,CAAC,OAAe,EAAE,EAAE,CAC5C,KAAK,CAAC,OAAO,CAAC,QAAQ,EAAE;IACtB,UAAU,EAAE,GAAG,EAAE,CAAC,MAAM,CAAC,IAAI,CAAC,EAAE,OAAO,EAAE,CAAC;CAClC,CAAC,CAAA;AAEb,MAAM,QAAQ,GAAG,aAAa,CAAC,IAAI,CAAC,CAAA;AAEpC,MAAM,YAAY,GAAG;IACnB,GAAG,EAAE,QAAQ;IACb,MAAM,EAAE;QACN,OAAO,EAAE,mBAAmB;QAC5B,MAAM,EAAE,EAAE,IAAI,EAAE,aAAa,EAAE;QAC/B,QAAQ,EAAE,EAAE,IAAI,EAAE,MAAM,EAAE;QAC1B,QAAQ,EAAE,EAAE,WAAW,EAAE,KAAK,EAAE;QAChC,SAAS,EAAE,EAAE,IAAI,EAAE,OAAO,EAAE;QAC5B,MAAM,EAAE,CAAC,SAAS,EAAE,KAAK,CAAC;QAC1B,OAAO,EAAE,0BAA0B;KACpC;CACF,CAAA;AAED,8EAA8E;AAC9E,QAAQ;AACR,8EAA8E;AAE9E,QAAQ,CAAC,kBAAkB,EAAE,GAAG,EAAE;IAChC,8EAA8E;IAC9E,EAAE,CAAC,MAAM,CAAC,0CAA0C,EAAE,GAAG,EAAE,CACzD,MAAM,CAAC,GAAG,CAAC,QAAQ,CAAC;QAClB,MAAM,MAAM,GAAG,KAAK,CAAC,CAAC,gBAAgB,CAAC,QAAQ,CAAC,CAAA;QAChD,MAAM,CAAC,MAAM,CAAC,IAAI,CAAC,CAAC,IAAI,CAAC,OAAO,CAAC,CAAA;QACjC,IAAI,MAAM,CAAC,IAAI,KAAK,OAAO;YAAE,OAAM;QACnC,MAAM,CAAC,MAAM,CAAC,MAAM,CAAC,GAAG,CAAC,CAAC,IAAI,CAAC,QAAQ,CAAC,CAAA;QACxC,MAAM,CAAC,MAAM,CAAC,MAAM,CAAC,OAAO,CAAC,CAAC,IAAI,CAAC,mBAAmB,CAAC,CAAA;QACvD,MAAM,CAAC,MAAM,CAAC,MAAM,CAAC,MAAM,CAAC,CAAC,IAAI,CAAC,aAAa,CAAC,CAAA;QAChD,MAAM,CAAC,MAAM,CAAC,MAAM,CAAC,QAAQ,CAAC,CAAC,IAAI,CAAC,MAAM,CAAC,CAAA;QAC3C,MAAM,CAAC,MAAM,CAAC,MAAM,CAAC,QAAQ,CAAC,CAAC,IAAI,CAAC,KAAK,CAAC,CAAA;QAC1C,MAAM,CAAC,MAAM,CAAC,MAAM,CAAC,IAAI,CAAC,CAAC,IAAI,CAAC,OAAO,CAAC,CAAA;QACxC,MAAM,CAAC,MAAM,CAAC,MAAM,CAAC,MAAM,CAAC,CAAC,OAAO,CAAC,CAAC,SAAS,EAAE,KAAK,CAAC,CAAC,CAAA;IAC1D,CAAC,CAAC,CAAC,IAAI,CACL,MAAM,CAAC,OAAO,CAAC,aAAa,CAAC,GAAG,EAAE,CAAC,CAAC,EAAE,IAAI,EAAE,YAAY,EAAE,QAAQ,EAAE,EAAE,EAAE,EAAE,IAAI,EAAE,MAAM,EAAE,GAAG,EAAE,EAAE,CAAC,CAAC,CAAC,EAClG,MAAM,CAAC,OAAO,CAAC,QAAQ,CAAC,CACzB,CAAC,CAAA;IAEJ,uDAAuD;IACvD,EAAE,CAAC,MAAM,CAAC,2BAA2B,EAAE,GAAG,EAAE,CAC1C,MAAM,CAAC,GAAG,CAAC,QAAQ,CAAC;QAClB,MAAM,MAAM,GAAG,KAAK,CAAC,CAAC,gBAAgB,CAAC,UAAU,CAAC,CAAA;QAClD,MAAM,CAAC,MAAM,CAAC,IAAI,CAAC,CAAC,IAAI,CAAC,UAAU,CAAC,CAAA;IACtC,CAAC,CAAC,CAAC,IAAI,CACL,MAAM,CAAC,OAAO,CACZ,aAAa,CAAC,GAAG,EAAE,CAAC,CAAC,EAAE,KAAK,EAAE,EAAE,aAAa,EAAE,CAAC,WAAW,CAAC,EAAE,EAAE,QAAQ,EAAE,EAAE,EAAE,EAAE,KAAK,EAAE,MAAM,EAAE,GAAG,EAAE,EAAE,CAAC,CAAC,CACzG,EACD,MAAM,CAAC,OAAO,CAAC,QAAQ,CAAC,CACzB,CAAC,CAAA;IAEJ,0EAA0E;IAC1E,gEAAgE;IAChE,EAAE,CAAC,MAAM,CAAC,sDAAsD,EAAE,GAAG,EAAE,CACrE,MAAM,CAAC,GAAG,CAAC,QAAQ,CAAC;QAClB,MAAM,MAAM,GAAG,KAAK,CAAC,CAAC,gBAAgB,CAAC,QAAQ,CAAC,CAAA;QAChD,MAAM,CAAC,MAAM,CAAC,IAAI,CAAC,CAAC,IAAI,CAAC,YAAY,CAAC,CAAA;IACxC,CAAC,CAAC,CAAC,IAAI,CACL,MAAM,CAAC,OAAO,CACZ,aAAa,CAAC,GAAG,EAAE,CAAC,CAAC,EAAE,KAAK,EAAE,EAAE,aAAa,EAAE,CAAC,cAAc,CAAC,EAAE,EAAE,QAAQ,EAAE,EAAE,EAAE,EAAE,KAAK,EAAE,MAAM,EAAE,GAAG,EAAE,EAAE,CAAC,CAAC,CAC5G,EACD,MAAM,CAAC,OAAO,CAAC,QAAQ,CAAC,CACzB,CAAC,CAAA;IAEJ,+EAA+E;IAC/E,gFAAgF;IAChF,EAAE,CAAC,MAAM,CAAC,4CAA4C,EAAE,GAAG,EAAE,CAC3D,MAAM,CAAC,GAAG,CAAC,QAAQ,CAAC;QAClB,MAAM,MAAM,GAAG,KAAK,CAAC,CAAC,gBAAgB,CAAC,QAAQ,CAAC,CAAA;QAChD,MAAM,CAAC,MAAM,CAAC,IAAI,CAAC,CAAC,IAAI,CAAC,aAAa,CAAC,CAAA;IACzC,CAAC,CAAC,CAAC,IAAI;IACL,+EAA+E;IAC/E,MAAM,CAAC,OAAO,CAAC,aAAa,CAAC,GAAG,EAAE,CAAC,CAAC,EAAE,IAAI,EAAE,YAAY,EAAE,QAAQ,EAAE,EAAE,EAAE,EAAE,IAAI,EAAE,MAAM,EAAE,GAAG,EAAE,EAAE,CAAC,CAAC,CAAC,EAClG,MAAM,CAAC,OAAO,CAAC,aAAa,CAAC,KAAK,CAAC,CAAC,CACrC,CAAC,CAAA;IAEJ,kFAAkF;IAClF,kGAAkG;IAClG,EAAE,CAAC,MAAM,CAAC,qEAAqE,EAAE,GAAG,EAAE,CACpF,MAAM,CAAC,GAAG,CAAC,QAAQ,CAAC;QAClB,MAAM,MAAM,GAAG,KAAK,CAAC,CAAC,gBAAgB,CAAC,QAAQ,CAAC,CAAA;QAChD,MAAM,CAAC,MAAM,CAAC,IAAI,CAAC,CAAC,IAAI,CAAC,YAAY,CAAC,CAAA;QACtC,IAAI,MAAM,CAAC,IAAI,KAAK,YAAY;YAAE,OAAM;QACxC,MAAM,CAAC,MAAM,CAAC,OAAO,CAAC,CAAC,IAAI,CAAC,uBAAuB,CAAC,CAAA;IACtD,CAAC,CAAC,CAAC,IAAI,CACL,MAAM,CAAC,OAAO,CAAC,aAAa,CAAC,GAAG,EAAE,CAAC,CAAC,EAAE,IAAI,EAAE,YAAY,EAAE,QAAQ,EAAE,EAAE,EAAE,EAAE,IAAI,EAAE,MAAM,EAAE,GAAG,EAAE,EAAE,CAAC,CAAC,CAAC,EAClG,MAAM,CAAC,OAAO,CAAC,iBAAiB,CAAC,uBAAuB,CAAC,CAAC,CAC3D,CAAC,CAAA;AACN,CAAC,CAAC,CAAA"}
@@ -1,93 +0,0 @@
1
- /**
2
- * Unit tests for the shared stop/correction project + billable resolvers.
3
- *
4
- * These cover the non-interactive (pass-through / early-return) branches of
5
- * {@link resolveStopProject} and {@link resolveStopBillable}, which require no
6
- * Terminal. The prompting branches drive Effect CLI Prompts and are exercised
7
- * end-to-end via the interactive `stop` command rather than here.
8
- */
9
- import { NodeServices, NodeTerminal } from "@effect/platform-node";
10
- import { describe, expect, it } from "@effect/vitest";
11
- import { ClockifyApiClient } from "@knpkv/clockify-api-client";
12
- import * as Effect from "effect/Effect";
13
- import * as Layer from "effect/Layer";
14
- import * as Redacted from "effect/Redacted";
15
- import { resolveStopBillable, resolveStopProject } from "../src/cli/timer/stop.js";
16
- import { ClockifyAuth } from "../src/services/ClockifyAuth.js";
17
- import { ConfigService } from "../src/services/ConfigService.js";
18
- const WORKSPACE_ID = "ws-1";
19
- let savedPatches = [];
20
- const mockClockify = {
21
- getProjects: () => Effect.succeed([])
22
- };
23
- const MockClockifyLayer = Layer.succeed(ClockifyApiClient, mockClockify);
24
- const MockClockifyAuthLayer = Layer.succeed(ClockifyAuth, {
25
- getConfig: Effect.succeed({
26
- apiKey: Redacted.make("key"),
27
- workspaceId: WORKSPACE_ID,
28
- userId: "user-1",
29
- baseUrl: "https://api.clockify.me/api"
30
- }),
31
- save: () => Effect.void,
32
- isConfigured: Effect.succeed(true)
33
- });
34
- const MockConfigLayer = Layer.succeed(ConfigService, {
35
- get: Effect.succeed({
36
- defaultJql: "",
37
- refreshInterval: 30,
38
- projectMap: {},
39
- workspaceId: null,
40
- defaultProjectId: null,
41
- defaultProjectName: null,
42
- defaultBillable: true
43
- }),
44
- set: (patch) => Effect.sync(() => {
45
- savedPatches.push(patch);
46
- }),
47
- configDir: Effect.succeed("/tmp/.jcf")
48
- });
49
- // NodeTerminal.layer satisfies the Terminal requirement the resolvers carry
50
- // in their R channel for the (unexercised here) Effect CLI prompting branches.
51
- // The non-interactive branches under test never touch it at runtime.
52
- const TestLayer = Layer.mergeAll(MockClockifyLayer, MockClockifyAuthLayer, MockConfigLayer, NodeServices.layer, NodeTerminal.layer);
53
- describe("resolveStopProject (non-interactive branches)", () => {
54
- // Project already set on the running timer: pass the flag value straight
55
- // through with no prompt (and no config write).
56
- it.effect("returns the flag value untouched when a project is already set", () => Effect.gen(function* () {
57
- savedPatches = [];
58
- const result = yield* resolveStopProject({ currentProjectId: "proj-current", flagProjectId: "proj-flag" });
59
- expect(result).toBe("proj-flag");
60
- expect(savedPatches).toHaveLength(0);
61
- }).pipe(Effect.provide(TestLayer)));
62
- // A --project flag short-circuits the prompt even with no current project.
63
- it.effect("returns the flag value when only the flag is provided", () => Effect.gen(function* () {
64
- savedPatches = [];
65
- const result = yield* resolveStopProject({ currentProjectId: null, flagProjectId: "proj-flag" });
66
- expect(result).toBe("proj-flag");
67
- expect(savedPatches).toHaveLength(0);
68
- }).pipe(Effect.provide(TestLayer)));
69
- // Nothing set and Clockify lists no projects: leave it unset, no prompt.
70
- it.effect("returns undefined when no project is set and none are available", () => Effect.gen(function* () {
71
- savedPatches = [];
72
- const result = yield* resolveStopProject({ currentProjectId: null, flagProjectId: undefined });
73
- expect(result).toBeUndefined();
74
- expect(savedPatches).toHaveLength(0);
75
- }).pipe(Effect.provide(TestLayer)));
76
- });
77
- describe("resolveStopBillable (non-interactive branches)", () => {
78
- // Billable already set on the running timer: pass the flag through, no prompt.
79
- it.effect("returns the flag value untouched when billable is already set", () => Effect.gen(function* () {
80
- savedPatches = [];
81
- const result = yield* resolveStopBillable({ currentBillable: true, flagBillable: false });
82
- expect(result).toBe(false);
83
- expect(savedPatches).toHaveLength(0);
84
- }).pipe(Effect.provide(TestLayer)));
85
- // A --billable flag short-circuits the prompt even when current is unset.
86
- it.effect("returns the flag value when only the flag is provided", () => Effect.gen(function* () {
87
- savedPatches = [];
88
- const result = yield* resolveStopBillable({ currentBillable: null, flagBillable: true });
89
- expect(result).toBe(true);
90
- expect(savedPatches).toHaveLength(0);
91
- }).pipe(Effect.provide(TestLayer)));
92
- });
93
- //# sourceMappingURL=stopPrompts.test.js.map
@@ -1 +0,0 @@
1
- {"version":3,"file":"stopPrompts.test.js","sourceRoot":"","sources":["../../test/stopPrompts.test.ts"],"names":[],"mappings":"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"}
@@ -1,84 +0,0 @@
1
- import { describe, expect, it } from "@effect/vitest";
2
- import { formatElapsed, isFullIsoTimestamp, parseDuration, parseStartTime } from "../src/utils/time.js";
3
- describe("parseDuration", () => {
4
- it("parses combined hours and minutes", () => {
5
- expect(parseDuration("1h30m")).toBe(5400);
6
- });
7
- it("parses hours only", () => {
8
- expect(parseDuration("2h")).toBe(7200);
9
- });
10
- it("parses minutes only, including >59", () => {
11
- expect(parseDuration("45m")).toBe(2700);
12
- expect(parseDuration("90m")).toBe(5400);
13
- });
14
- it("trims surrounding whitespace", () => {
15
- expect(parseDuration(" 15m ")).toBe(900);
16
- });
17
- it("rejects empty or malformed input", () => {
18
- expect(parseDuration("")).toBeNull();
19
- expect(parseDuration("abc")).toBeNull();
20
- expect(parseDuration("1h30")).toBeNull();
21
- expect(parseDuration("30s")).toBeNull();
22
- });
23
- });
24
- describe("parseStartTime", () => {
25
- const now = new Date("2025-06-19T15:00:00.000Z");
26
- it("interprets HH:MM as that local time today", () => {
27
- const result = parseStartTime("09:30", now);
28
- expect(result).not.toBeNull();
29
- expect(result.getHours()).toBe(9);
30
- expect(result.getMinutes()).toBe(30);
31
- expect(result.getSeconds()).toBe(0);
32
- // Same calendar day as `now`
33
- expect(result.getDate()).toBe(now.getDate());
34
- });
35
- it("parses a full ISO timestamp", () => {
36
- const result = parseStartTime("2025-01-01T10:00:00.000Z", now);
37
- expect(result?.toISOString()).toBe("2025-01-01T10:00:00.000Z");
38
- });
39
- it("parses an ISO timestamp without seconds or zone", () => {
40
- const result = parseStartTime("2025-01-01T10:00", now);
41
- expect(result).not.toBeNull();
42
- });
43
- it("returns a future instant for an HH:MM later today (caller must guard)", () => {
44
- // now is 15:00 — 18:00 today is still in the future; the parser itself does
45
- // not reject it (the future-guard lives at the command/service layer).
46
- const result = parseStartTime("18:00", now);
47
- expect(result).not.toBeNull();
48
- expect(result.getTime()).toBeGreaterThan(now.getTime());
49
- });
50
- it("rejects out-of-range clock times", () => {
51
- expect(parseStartTime("24:00", now)).toBeNull();
52
- expect(parseStartTime("10:60", now)).toBeNull();
53
- });
54
- it("rejects date-only and loose Date-parseable strings", () => {
55
- // These are accepted by `new Date()` but must not become a surprising instant.
56
- expect(parseStartTime("2024", now)).toBeNull();
57
- expect(parseStartTime("Jan 5", now)).toBeNull();
58
- expect(parseStartTime("2025-01-01", now)).toBeNull();
59
- });
60
- it("rejects unparseable input", () => {
61
- expect(parseStartTime("not-a-time", now)).toBeNull();
62
- });
63
- });
64
- describe("isFullIsoTimestamp", () => {
65
- it("recognises full ISO timestamps", () => {
66
- expect(isFullIsoTimestamp("2025-01-01T10:00:00.000Z")).toBe(true);
67
- expect(isFullIsoTimestamp("2025-01-01T10:00")).toBe(true);
68
- expect(isFullIsoTimestamp(" 2025-06-01T09:00+02:00 ")).toBe(true);
69
- });
70
- it("rejects HH:MM and date-only strings", () => {
71
- expect(isFullIsoTimestamp("09:30")).toBe(false);
72
- expect(isFullIsoTimestamp("2025-01-01")).toBe(false);
73
- expect(isFullIsoTimestamp("2024")).toBe(false);
74
- });
75
- });
76
- describe("formatElapsed", () => {
77
- it("formats positive seconds as HH:MM:SS", () => {
78
- expect(formatElapsed(3661)).toBe("01:01:01");
79
- });
80
- it("clamps negative input to zero", () => {
81
- expect(formatElapsed(-5)).toBe("00:00:00");
82
- });
83
- });
84
- //# sourceMappingURL=time.test.js.map
@@ -1 +0,0 @@
1
- {"version":3,"file":"time.test.js","sourceRoot":"","sources":["../../test/time.test.ts"],"names":[],"mappings":"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"}