@geneverse/workctl 0.2.5

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 (182) hide show
  1. package/LICENSE +21 -0
  2. package/README.md +340 -0
  3. package/dist/packages/capabilities/assistant/src/commands.d.ts +10 -0
  4. package/dist/packages/capabilities/assistant/src/commands.js +33 -0
  5. package/dist/packages/capabilities/assistant/src/commands.js.map +1 -0
  6. package/dist/packages/capabilities/assistant/src/index.d.ts +2 -0
  7. package/dist/packages/capabilities/assistant/src/index.js +3 -0
  8. package/dist/packages/capabilities/assistant/src/index.js.map +1 -0
  9. package/dist/packages/capabilities/assistant/src/status.d.ts +18 -0
  10. package/dist/packages/capabilities/assistant/src/status.js +48 -0
  11. package/dist/packages/capabilities/assistant/src/status.js.map +1 -0
  12. package/dist/packages/capabilities/jenkins/src/commands.d.ts +9 -0
  13. package/dist/packages/capabilities/jenkins/src/commands.js +43 -0
  14. package/dist/packages/capabilities/jenkins/src/commands.js.map +1 -0
  15. package/dist/packages/capabilities/jenkins/src/definition.d.ts +10 -0
  16. package/dist/packages/capabilities/jenkins/src/definition.js +59 -0
  17. package/dist/packages/capabilities/jenkins/src/definition.js.map +1 -0
  18. package/dist/packages/capabilities/jenkins/src/index.d.ts +2 -0
  19. package/dist/packages/capabilities/jenkins/src/index.js +3 -0
  20. package/dist/packages/capabilities/jenkins/src/index.js.map +1 -0
  21. package/dist/packages/capabilities/jira/src/adapters/filesystem/config.store.d.ts +2 -0
  22. package/dist/packages/capabilities/jira/src/adapters/filesystem/config.store.js +43 -0
  23. package/dist/packages/capabilities/jira/src/adapters/filesystem/config.store.js.map +1 -0
  24. package/dist/packages/capabilities/jira/src/adapters/filesystem/local.paths.d.ts +16 -0
  25. package/dist/packages/capabilities/jira/src/adapters/filesystem/local.paths.js +46 -0
  26. package/dist/packages/capabilities/jira/src/adapters/filesystem/local.paths.js.map +1 -0
  27. package/dist/packages/capabilities/jira/src/adapters/filesystem/sync-lock.d.ts +2 -0
  28. package/dist/packages/capabilities/jira/src/adapters/filesystem/sync-lock.js +120 -0
  29. package/dist/packages/capabilities/jira/src/adapters/filesystem/sync-lock.js.map +1 -0
  30. package/dist/packages/capabilities/jira/src/adapters/jira/jira.client.d.ts +31 -0
  31. package/dist/packages/capabilities/jira/src/adapters/jira/jira.client.js +344 -0
  32. package/dist/packages/capabilities/jira/src/adapters/jira/jira.client.js.map +1 -0
  33. package/dist/packages/capabilities/jira/src/adapters/kawari/catalog.d.ts +9 -0
  34. package/dist/packages/capabilities/jira/src/adapters/kawari/catalog.js +17 -0
  35. package/dist/packages/capabilities/jira/src/adapters/kawari/catalog.js.map +1 -0
  36. package/dist/packages/capabilities/jira/src/adapters/kawari/orchestrator.d.ts +14 -0
  37. package/dist/packages/capabilities/jira/src/adapters/kawari/orchestrator.js +116 -0
  38. package/dist/packages/capabilities/jira/src/adapters/kawari/orchestrator.js.map +1 -0
  39. package/dist/packages/capabilities/jira/src/adapters/kawari/scraper.d.ts +32 -0
  40. package/dist/packages/capabilities/jira/src/adapters/kawari/scraper.js +2 -0
  41. package/dist/packages/capabilities/jira/src/adapters/kawari/scraper.js.map +1 -0
  42. package/dist/packages/capabilities/jira/src/adapters/kawari/v1/detect.d.ts +2 -0
  43. package/dist/packages/capabilities/jira/src/adapters/kawari/v1/detect.js +45 -0
  44. package/dist/packages/capabilities/jira/src/adapters/kawari/v1/detect.js.map +1 -0
  45. package/dist/packages/capabilities/jira/src/adapters/kawari/v1/extract.d.ts +3 -0
  46. package/dist/packages/capabilities/jira/src/adapters/kawari/v1/extract.js +115 -0
  47. package/dist/packages/capabilities/jira/src/adapters/kawari/v1/extract.js.map +1 -0
  48. package/dist/packages/capabilities/jira/src/adapters/kawari/v1/index.d.ts +2 -0
  49. package/dist/packages/capabilities/jira/src/adapters/kawari/v1/index.js +27 -0
  50. package/dist/packages/capabilities/jira/src/adapters/kawari/v1/index.js.map +1 -0
  51. package/dist/packages/capabilities/jira/src/adapters/kawari/v1/navigation.d.ts +3 -0
  52. package/dist/packages/capabilities/jira/src/adapters/kawari/v1/navigation.js +104 -0
  53. package/dist/packages/capabilities/jira/src/adapters/kawari/v1/navigation.js.map +1 -0
  54. package/dist/packages/capabilities/jira/src/adapters/kawari/v1/ready.d.ts +2 -0
  55. package/dist/packages/capabilities/jira/src/adapters/kawari/v1/ready.js +47 -0
  56. package/dist/packages/capabilities/jira/src/adapters/kawari/v1/ready.js.map +1 -0
  57. package/dist/packages/capabilities/jira/src/adapters/kawari/v1/shared.d.ts +4 -0
  58. package/dist/packages/capabilities/jira/src/adapters/kawari/v1/shared.js +5 -0
  59. package/dist/packages/capabilities/jira/src/adapters/kawari/v1/shared.js.map +1 -0
  60. package/dist/packages/capabilities/jira/src/adapters/terminal/node-cli.io.d.ts +2 -0
  61. package/dist/packages/capabilities/jira/src/adapters/terminal/node-cli.io.js +40 -0
  62. package/dist/packages/capabilities/jira/src/adapters/terminal/node-cli.io.js.map +1 -0
  63. package/dist/packages/capabilities/jira/src/batch-interaction.d.ts +53 -0
  64. package/dist/packages/capabilities/jira/src/batch-interaction.js +201 -0
  65. package/dist/packages/capabilities/jira/src/batch-interaction.js.map +1 -0
  66. package/dist/packages/capabilities/jira/src/capability.d.ts +16 -0
  67. package/dist/packages/capabilities/jira/src/capability.js +56 -0
  68. package/dist/packages/capabilities/jira/src/capability.js.map +1 -0
  69. package/dist/packages/capabilities/jira/src/cli/contracts.d.ts +42 -0
  70. package/dist/packages/capabilities/jira/src/cli/contracts.js +2 -0
  71. package/dist/packages/capabilities/jira/src/cli/contracts.js.map +1 -0
  72. package/dist/packages/capabilities/jira/src/cli/errors.d.ts +3 -0
  73. package/dist/packages/capabilities/jira/src/cli/errors.js +7 -0
  74. package/dist/packages/capabilities/jira/src/cli/errors.js.map +1 -0
  75. package/dist/packages/capabilities/jira/src/cli/program.d.ts +6 -0
  76. package/dist/packages/capabilities/jira/src/cli/program.js +48 -0
  77. package/dist/packages/capabilities/jira/src/cli/program.js.map +1 -0
  78. package/dist/packages/capabilities/jira/src/cli/run-cli.d.ts +2 -0
  79. package/dist/packages/capabilities/jira/src/cli/run-cli.js +72 -0
  80. package/dist/packages/capabilities/jira/src/cli/run-cli.js.map +1 -0
  81. package/dist/packages/capabilities/jira/src/commands/audit-links/audit-links.command.d.ts +2 -0
  82. package/dist/packages/capabilities/jira/src/commands/audit-links/audit-links.command.js +165 -0
  83. package/dist/packages/capabilities/jira/src/commands/audit-links/audit-links.command.js.map +1 -0
  84. package/dist/packages/capabilities/jira/src/commands/audit-links/audit-links.service.d.ts +30 -0
  85. package/dist/packages/capabilities/jira/src/commands/audit-links/audit-links.service.js +174 -0
  86. package/dist/packages/capabilities/jira/src/commands/audit-links/audit-links.service.js.map +1 -0
  87. package/dist/packages/capabilities/jira/src/commands/command-context.d.ts +10 -0
  88. package/dist/packages/capabilities/jira/src/commands/command-context.js +2 -0
  89. package/dist/packages/capabilities/jira/src/commands/command-context.js.map +1 -0
  90. package/dist/packages/capabilities/jira/src/commands/config-show/config-show.command.d.ts +2 -0
  91. package/dist/packages/capabilities/jira/src/commands/config-show/config-show.command.js +26 -0
  92. package/dist/packages/capabilities/jira/src/commands/config-show/config-show.command.js.map +1 -0
  93. package/dist/packages/capabilities/jira/src/commands/configure/configure.command.d.ts +2 -0
  94. package/dist/packages/capabilities/jira/src/commands/configure/configure.command.js +26 -0
  95. package/dist/packages/capabilities/jira/src/commands/configure/configure.command.js.map +1 -0
  96. package/dist/packages/capabilities/jira/src/commands/configure/configure.service.d.ts +42 -0
  97. package/dist/packages/capabilities/jira/src/commands/configure/configure.service.js +205 -0
  98. package/dist/packages/capabilities/jira/src/commands/configure/configure.service.js.map +1 -0
  99. package/dist/packages/capabilities/jira/src/commands/doctor/doctor.command.d.ts +2 -0
  100. package/dist/packages/capabilities/jira/src/commands/doctor/doctor.command.js +17 -0
  101. package/dist/packages/capabilities/jira/src/commands/doctor/doctor.command.js.map +1 -0
  102. package/dist/packages/capabilities/jira/src/commands/doctor/doctor.service.d.ts +18 -0
  103. package/dist/packages/capabilities/jira/src/commands/doctor/doctor.service.js +84 -0
  104. package/dist/packages/capabilities/jira/src/commands/doctor/doctor.service.js.map +1 -0
  105. package/dist/packages/capabilities/jira/src/commands/rollback/rollback.command.d.ts +2 -0
  106. package/dist/packages/capabilities/jira/src/commands/rollback/rollback.command.js +198 -0
  107. package/dist/packages/capabilities/jira/src/commands/rollback/rollback.command.js.map +1 -0
  108. package/dist/packages/capabilities/jira/src/commands/rollback/rollback.service.d.ts +37 -0
  109. package/dist/packages/capabilities/jira/src/commands/rollback/rollback.service.js +112 -0
  110. package/dist/packages/capabilities/jira/src/commands/rollback/rollback.service.js.map +1 -0
  111. package/dist/packages/capabilities/jira/src/commands/sync/audit-export.service.d.ts +18 -0
  112. package/dist/packages/capabilities/jira/src/commands/sync/audit-export.service.js +96 -0
  113. package/dist/packages/capabilities/jira/src/commands/sync/audit-export.service.js.map +1 -0
  114. package/dist/packages/capabilities/jira/src/commands/sync/preview.service.d.ts +23 -0
  115. package/dist/packages/capabilities/jira/src/commands/sync/preview.service.js +201 -0
  116. package/dist/packages/capabilities/jira/src/commands/sync/preview.service.js.map +1 -0
  117. package/dist/packages/capabilities/jira/src/commands/sync/sync.command.d.ts +2 -0
  118. package/dist/packages/capabilities/jira/src/commands/sync/sync.command.js +537 -0
  119. package/dist/packages/capabilities/jira/src/commands/sync/sync.command.js.map +1 -0
  120. package/dist/packages/capabilities/jira/src/commands/sync/verification.service.d.ts +34 -0
  121. package/dist/packages/capabilities/jira/src/commands/sync/verification.service.js +164 -0
  122. package/dist/packages/capabilities/jira/src/commands/sync/verification.service.js.map +1 -0
  123. package/dist/packages/capabilities/jira/src/config.d.ts +37 -0
  124. package/dist/packages/capabilities/jira/src/config.js +217 -0
  125. package/dist/packages/capabilities/jira/src/config.js.map +1 -0
  126. package/dist/packages/capabilities/jira/src/dependencies.d.ts +2 -0
  127. package/dist/packages/capabilities/jira/src/dependencies.js +92 -0
  128. package/dist/packages/capabilities/jira/src/dependencies.js.map +1 -0
  129. package/dist/packages/capabilities/jira/src/domain/date-range.d.ts +10 -0
  130. package/dist/packages/capabilities/jira/src/domain/date-range.js +63 -0
  131. package/dist/packages/capabilities/jira/src/domain/date-range.js.map +1 -0
  132. package/dist/packages/capabilities/jira/src/domain/marker.d.ts +20 -0
  133. package/dist/packages/capabilities/jira/src/domain/marker.js +100 -0
  134. package/dist/packages/capabilities/jira/src/domain/marker.js.map +1 -0
  135. package/dist/packages/capabilities/jira/src/domain/timesheet-entry.d.ts +45 -0
  136. package/dist/packages/capabilities/jira/src/domain/timesheet-entry.js +117 -0
  137. package/dist/packages/capabilities/jira/src/domain/timesheet-entry.js.map +1 -0
  138. package/dist/packages/capabilities/jira/src/index.d.ts +5 -0
  139. package/dist/packages/capabilities/jira/src/index.js +4 -0
  140. package/dist/packages/capabilities/jira/src/index.js.map +1 -0
  141. package/dist/packages/capabilities/jira/src/ports/jira.d.ts +49 -0
  142. package/dist/packages/capabilities/jira/src/ports/jira.js +11 -0
  143. package/dist/packages/capabilities/jira/src/ports/jira.js.map +1 -0
  144. package/dist/packages/capabilities/jira/src/ports/sync-lock.d.ts +6 -0
  145. package/dist/packages/capabilities/jira/src/ports/sync-lock.js +7 -0
  146. package/dist/packages/capabilities/jira/src/ports/sync-lock.js.map +1 -0
  147. package/dist/packages/capabilities/jira/src/ports/timesheet.d.ts +11 -0
  148. package/dist/packages/capabilities/jira/src/ports/timesheet.js +7 -0
  149. package/dist/packages/capabilities/jira/src/ports/timesheet.js.map +1 -0
  150. package/dist/packages/capabilities/jira/src/presentation.d.ts +37 -0
  151. package/dist/packages/capabilities/jira/src/presentation.js +111 -0
  152. package/dist/packages/capabilities/jira/src/presentation.js.map +1 -0
  153. package/dist/packages/cli/src/bin.d.ts +2 -0
  154. package/dist/packages/cli/src/bin.js +4 -0
  155. package/dist/packages/cli/src/bin.js.map +1 -0
  156. package/dist/packages/cli/src/commands/browsers/browsers.command.d.ts +7 -0
  157. package/dist/packages/cli/src/commands/browsers/browsers.command.js +22 -0
  158. package/dist/packages/cli/src/commands/browsers/browsers.command.js.map +1 -0
  159. package/dist/packages/cli/src/commands/browsers/browsers.service.d.ts +16 -0
  160. package/dist/packages/cli/src/commands/browsers/browsers.service.js +37 -0
  161. package/dist/packages/cli/src/commands/browsers/browsers.service.js.map +1 -0
  162. package/dist/packages/cli/src/commands/setup/setup.command.d.ts +4 -0
  163. package/dist/packages/cli/src/commands/setup/setup.command.js +41 -0
  164. package/dist/packages/cli/src/commands/setup/setup.command.js.map +1 -0
  165. package/dist/packages/cli/src/commands/setup/setup.service.d.ts +23 -0
  166. package/dist/packages/cli/src/commands/setup/setup.service.js +32 -0
  167. package/dist/packages/cli/src/commands/setup/setup.service.js.map +1 -0
  168. package/dist/packages/cli/src/commands/update/update.command.d.ts +7 -0
  169. package/dist/packages/cli/src/commands/update/update.command.js +34 -0
  170. package/dist/packages/cli/src/commands/update/update.command.js.map +1 -0
  171. package/dist/packages/cli/src/commands/update/update.service.d.ts +35 -0
  172. package/dist/packages/cli/src/commands/update/update.service.js +134 -0
  173. package/dist/packages/cli/src/commands/update/update.service.js.map +1 -0
  174. package/dist/packages/cli/src/index.d.ts +1 -0
  175. package/dist/packages/cli/src/index.js +2 -0
  176. package/dist/packages/cli/src/index.js.map +1 -0
  177. package/dist/packages/cli/src/program.d.ts +21 -0
  178. package/dist/packages/cli/src/program.js +74 -0
  179. package/dist/packages/cli/src/program.js.map +1 -0
  180. package/dist/packages/cli/src/release-version.d.ts +1 -0
  181. package/dist/packages/cli/src/release-version.js +2 -0
  182. package/package.json +57 -0
@@ -0,0 +1,9 @@
1
+ import type { KawariScraper, TimesheetBrowserIO } from "./scraper.js";
2
+ import { createV1Scraper } from "./v1/index.js";
3
+ export declare const ACTIVE_KAWARI_VERSION: "v1";
4
+ export declare const KAWARI_ADAPTER_FACTORIES: {
5
+ v1: typeof createV1Scraper;
6
+ };
7
+ export type KawariVersion = keyof typeof KAWARI_ADAPTER_FACTORIES;
8
+ export declare const KAWARI_VERSIONS: readonly "v1"[];
9
+ export declare function createKawariScraper(version: string | undefined, timesheetUrl: string, io: TimesheetBrowserIO): KawariScraper;
@@ -0,0 +1,17 @@
1
+ import { createV1Scraper } from "./v1/index.js";
2
+ import { TimesheetBrowserError } from "../../ports/timesheet.js";
3
+ export const ACTIVE_KAWARI_VERSION = "v1";
4
+ export const KAWARI_ADAPTER_FACTORIES = {
5
+ v1: createV1Scraper,
6
+ };
7
+ export const KAWARI_VERSIONS = Object.freeze(Object.keys(KAWARI_ADAPTER_FACTORIES));
8
+ export function createKawariScraper(version, timesheetUrl, io) {
9
+ const requestedVersion = version ?? ACTIVE_KAWARI_VERSION;
10
+ const factory = KAWARI_ADAPTER_FACTORIES[requestedVersion];
11
+ if (!factory) {
12
+ throw new TimesheetBrowserError(`Kawari scraper version "${requestedVersion}" is not bundled with this workctl release. ` +
13
+ `Available versions: ${KAWARI_VERSIONS.join(", ")}.`);
14
+ }
15
+ return factory(timesheetUrl, io);
16
+ }
17
+ //# sourceMappingURL=catalog.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"catalog.js","sourceRoot":"","sources":["../../../../../../../packages/capabilities/jira/src/adapters/kawari/catalog.ts"],"names":[],"mappings":"AACA,OAAO,EAAE,eAAe,EAAE,MAAM,eAAe,CAAC;AAChD,OAAO,EAAE,qBAAqB,EAAE,MAAM,0BAA0B,CAAC;AAEjE,MAAM,CAAC,MAAM,qBAAqB,GAAG,IAAa,CAAC;AAEnD,MAAM,CAAC,MAAM,wBAAwB,GAAG;IACtC,EAAE,EAAE,eAAe;CAIpB,CAAC;AAIF,MAAM,CAAC,MAAM,eAAe,GAAG,MAAM,CAAC,MAAM,CAC1C,MAAM,CAAC,IAAI,CAAC,wBAAwB,CAAoB,CACzD,CAAC;AAEF,MAAM,UAAU,mBAAmB,CACjC,OAA2B,EAC3B,YAAoB,EACpB,EAAsB;IAEtB,MAAM,gBAAgB,GAAG,OAAO,IAAI,qBAAqB,CAAC;IAC1D,MAAM,OAAO,GACX,wBAAwB,CAAC,gBAAiC,CAAC,CAAC;IAC9D,IAAI,CAAC,OAAO,EAAE,CAAC;QACb,MAAM,IAAI,qBAAqB,CAC7B,2BAA2B,gBAAgB,8CAA8C;YACzF,uBAAuB,eAAe,CAAC,IAAI,CAAC,IAAI,CAAC,GAAG,CACrD,CAAC;IACJ,CAAC;IACD,OAAO,OAAO,CAAC,YAAY,EAAE,EAAE,CAAC,CAAC;AACnC,CAAC"}
@@ -0,0 +1,14 @@
1
+ import type { Page } from "playwright";
2
+ import { type TimesheetInspection } from "../../ports/timesheet.js";
3
+ import { type TimesheetBrowserIO } from "./scraper.js";
4
+ export interface BrowserSession {
5
+ page: Page;
6
+ close: () => Promise<void>;
7
+ }
8
+ export interface BrowserRuntime {
9
+ launchPersistent(profilePath: string): Promise<BrowserSession>;
10
+ }
11
+ export declare function playwrightRuntime(): BrowserRuntime;
12
+ export declare function inspectTimesheet(timesheetUrl: string, targetMonth: string, paths: {
13
+ browserProfile: string;
14
+ }, io: TimesheetBrowserIO, runtime?: BrowserRuntime, scraperVersion?: string): Promise<TimesheetInspection>;
@@ -0,0 +1,116 @@
1
+ import { mkdir } from "node:fs/promises";
2
+ import { chromium } from "playwright";
3
+ import { TimesheetBrowserError, } from "../../ports/timesheet.js";
4
+ import { createKawariScraper } from "./catalog.js";
5
+ const TIMESHEET_READY_TIMEOUT_MS = 60_000;
6
+ const LOGIN_SELECTOR = 'input[type="password"], form[action*="login" i], [data-testid*="login-form" i]';
7
+ function parseYearMonth(targetMonth) {
8
+ const [year, month] = targetMonth.split("-");
9
+ return { year: Number(year), month: Number(month) };
10
+ }
11
+ export function playwrightRuntime() {
12
+ return {
13
+ async launchPersistent(profilePath) {
14
+ let context;
15
+ try {
16
+ context = await chromium.launchPersistentContext(profilePath, {
17
+ headless: false,
18
+ viewport: null,
19
+ });
20
+ const pages = context.pages();
21
+ const page = pages[0] ?? (await context.newPage());
22
+ return { page, close: () => context.close() };
23
+ }
24
+ catch {
25
+ await context?.close().catch(() => undefined);
26
+ throw new TimesheetBrowserError("Unable to open the local Kawari browser session. No session data was printed.");
27
+ }
28
+ },
29
+ };
30
+ }
31
+ async function loginAndRetry(page, timesheetUrl, io) {
32
+ try {
33
+ await io.waitForLogin();
34
+ }
35
+ catch {
36
+ throw new TimesheetBrowserError("Manual login requires an interactive terminal.");
37
+ }
38
+ io.reportProgress?.({ stage: "reopening-after-login" });
39
+ try {
40
+ await page.goto(timesheetUrl, {
41
+ waitUntil: "domcontentloaded",
42
+ timeout: 30_000,
43
+ });
44
+ }
45
+ catch {
46
+ throw new TimesheetBrowserError("Unable to reopen Kawari Timesheet after login. Check TIMESHEET_URL and network access.");
47
+ }
48
+ }
49
+ async function inspectReadyTimesheet(page, scraper, targetMonth, io) {
50
+ const controller = new AbortController();
51
+ let timeout;
52
+ const deadline = new Promise((_, reject) => {
53
+ timeout = setTimeout(() => {
54
+ controller.abort();
55
+ reject(new TimesheetBrowserError("Kawari Timesheet did not finish loading within 60 seconds."));
56
+ }, TIMESHEET_READY_TIMEOUT_MS);
57
+ });
58
+ const inspect = async () => {
59
+ io.reportProgress?.({ stage: "waiting" });
60
+ const state = await Promise.race([
61
+ scraper.waitForReady(page, controller.signal).then(() => "ready"),
62
+ page.locator(LOGIN_SELECTOR).first()
63
+ .waitFor({ state: "visible", timeout: TIMESHEET_READY_TIMEOUT_MS })
64
+ .then(() => "login"),
65
+ ]);
66
+ if (state === "login")
67
+ return "login";
68
+ await scraper.assertCompatible(page);
69
+ io.reportProgress?.({ stage: "selecting-month", targetMonth });
70
+ await scraper.navigateToMonth(page, parseYearMonth(targetMonth), controller.signal);
71
+ io.reportProgress?.({ stage: "reading-entries" });
72
+ return scraper.extractGrid(page);
73
+ };
74
+ try {
75
+ return await Promise.race([inspect(), deadline]);
76
+ }
77
+ finally {
78
+ controller.abort();
79
+ if (timeout)
80
+ clearTimeout(timeout);
81
+ }
82
+ }
83
+ export async function inspectTimesheet(timesheetUrl, targetMonth, paths, io, runtime = playwrightRuntime(), scraperVersion) {
84
+ io.reportProgress?.({ stage: "opening" });
85
+ await mkdir(paths.browserProfile, { recursive: true, mode: 0o700 });
86
+ const session = await runtime.launchPersistent(paths.browserProfile);
87
+ try {
88
+ try {
89
+ await session.page.goto(timesheetUrl, { waitUntil: "domcontentloaded", timeout: 30_000 });
90
+ }
91
+ catch {
92
+ throw new TimesheetBrowserError("Unable to open Kawari Timesheet. Check TIMESHEET_URL and network access.");
93
+ }
94
+ const scraper = createKawariScraper(scraperVersion, timesheetUrl, io);
95
+ let result = await inspectReadyTimesheet(session.page, scraper, targetMonth, io);
96
+ if (result === "login") {
97
+ await loginAndRetry(session.page, timesheetUrl, io);
98
+ result = await inspectReadyTimesheet(session.page, scraper, targetMonth, io);
99
+ if (result === "login") {
100
+ throw new TimesheetBrowserError("Kawari login was still required after manual login.");
101
+ }
102
+ }
103
+ const grid = result;
104
+ return {
105
+ urlOrigin: new URL(session.page.url()).origin,
106
+ titlePresent: true,
107
+ taskInputCount: grid.rows.length,
108
+ durationInputCount: grid.rows.reduce((sum, row) => sum + row.durations.length, 0),
109
+ grid,
110
+ };
111
+ }
112
+ finally {
113
+ await session.close().catch(() => undefined);
114
+ }
115
+ }
116
+ //# sourceMappingURL=orchestrator.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"orchestrator.js","sourceRoot":"","sources":["../../../../../../../packages/capabilities/jira/src/adapters/kawari/orchestrator.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,32 @@
1
+ import type { Page } from "playwright";
2
+ import type { TimesheetGrid } from "../../domain/timesheet-entry.js";
3
+ export type TimesheetBrowserProgress = {
4
+ stage: "opening";
5
+ } | {
6
+ stage: "waiting";
7
+ } | {
8
+ stage: "reopening-after-login";
9
+ } | {
10
+ stage: "selecting-month";
11
+ targetMonth: string;
12
+ } | {
13
+ stage: "reading-entries";
14
+ };
15
+ export interface TimesheetBrowserIO {
16
+ stdout: (message: string) => void;
17
+ waitForLogin: () => Promise<void>;
18
+ waitForMonthSelection: () => Promise<void>;
19
+ reportProgress?: (progress: TimesheetBrowserProgress) => void;
20
+ }
21
+ export interface KawariScraper {
22
+ readonly version: string;
23
+ readonly label: string;
24
+ assertCompatible(page: Page): Promise<void>;
25
+ waitForReady(page: Page, signal: AbortSignal): Promise<void>;
26
+ navigateToMonth(page: Page, target: YearMonth, signal: AbortSignal): Promise<void>;
27
+ extractGrid(page: Page): Promise<TimesheetGrid>;
28
+ }
29
+ export interface YearMonth {
30
+ year: number;
31
+ month: number;
32
+ }
@@ -0,0 +1,2 @@
1
+ export {};
2
+ //# sourceMappingURL=scraper.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"scraper.js","sourceRoot":"","sources":["../../../../../../../packages/capabilities/jira/src/adapters/kawari/scraper.ts"],"names":[],"mappings":""}
@@ -0,0 +1,2 @@
1
+ import type { Page } from "playwright";
2
+ export declare function assertV1Compatible(page: Page, expectedUrl: string): Promise<void>;
@@ -0,0 +1,45 @@
1
+ import { TimesheetBrowserError } from "../../../ports/timesheet.js";
2
+ export async function assertV1Compatible(page, expectedUrl) {
3
+ const actual = new URL(page.url());
4
+ const expected = new URL(expectedUrl);
5
+ const missingSignals = actual.origin === expected.origin && actual.pathname === expected.pathname
6
+ ? await page.evaluate(() => {
7
+ const missingSignals = [];
8
+ const monthNames = [
9
+ "Jan", "Feb", "Mar", "Apr", "May", "Jun",
10
+ "Jul", "Aug", "Sep", "Oct", "Nov", "Dec",
11
+ ];
12
+ const monthPattern = /^(Jan|Feb|Mar|Apr|May|Jun|Jul|Aug|Sep|Oct|Nov|Dec) (\d{4})$/;
13
+ const heading = [...document.querySelectorAll("body *")]
14
+ .map((element) => element.textContent?.trim() ?? "")
15
+ .find((text) => monthPattern.test(text));
16
+ const match = heading?.match(monthPattern);
17
+ if (!match)
18
+ return ["month heading"];
19
+ const month = monthNames.indexOf(match[1]) + 1;
20
+ const year = Number(match[2]);
21
+ const daysInMonth = new Date(Date.UTC(year, month, 0)).getUTCDate();
22
+ const hasDateColumns = [...document.querySelectorAll("div")].some((element) => {
23
+ const children = [...element.children];
24
+ for (let start = 0; start <= children.length - daysInMonth; start += 1) {
25
+ const candidate = children.slice(start, start + daysInMonth);
26
+ if (candidate.every((child, index) => {
27
+ const day = child.textContent?.trim().match(/(\d{1,2})$/);
28
+ return day !== null && Number(day[1]) === index + 1;
29
+ })) {
30
+ return true;
31
+ }
32
+ }
33
+ return false;
34
+ });
35
+ if (!hasDateColumns)
36
+ missingSignals.push("date columns");
37
+ return missingSignals;
38
+ })
39
+ : ["timesheet URL"];
40
+ if (missingSignals.length > 0) {
41
+ throw new TimesheetBrowserError(`Kawari Timesheet does not match scraper v1 (missing: ${missingSignals.join(", ")}). ` +
42
+ "Update workctl or select another bundled version with --scraper-version.");
43
+ }
44
+ }
45
+ //# sourceMappingURL=detect.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"detect.js","sourceRoot":"","sources":["../../../../../../../../packages/capabilities/jira/src/adapters/kawari/v1/detect.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,3 @@
1
+ import type { Page } from "playwright";
2
+ import type { TimesheetInspection } from "../../../ports/timesheet.js";
3
+ export declare function inspectReadyPage(page: Page, expectedUrl: string): Promise<TimesheetInspection | undefined>;
@@ -0,0 +1,115 @@
1
+ const MONTH_NAMES = [
2
+ "Jan", "Feb", "Mar", "Apr", "May", "Jun",
3
+ "Jul", "Aug", "Sep", "Oct", "Nov", "Dec",
4
+ ];
5
+ export async function inspectReadyPage(page, expectedUrl) {
6
+ const actual = new URL(page.url());
7
+ const expected = new URL(expectedUrl);
8
+ if (actual.origin !== expected.origin || actual.pathname !== expected.pathname)
9
+ return undefined;
10
+ const contract = await page.evaluate(() => {
11
+ const monthNames = [
12
+ "Jan", "Feb", "Mar", "Apr", "May", "Jun",
13
+ "Jul", "Aug", "Sep", "Oct", "Nov", "Dec",
14
+ ];
15
+ const referenceText = [...document.querySelectorAll("body *")]
16
+ .map((element) => element.textContent?.trim() ?? "")
17
+ .find((text) => /^(Jan|Feb|Mar|Apr|May|Jun|Jul|Aug|Sep|Oct|Nov|Dec) \d{4}$/.test(text));
18
+ const referenceMatch = referenceText?.match(/^(Jan|Feb|Mar|Apr|May|Jun|Jul|Aug|Sep|Oct|Nov|Dec) (\d{4})$/);
19
+ const month = referenceMatch ? monthNames.indexOf(referenceMatch[1]) + 1 : undefined;
20
+ const year = referenceMatch ? Number(referenceMatch[2]) : undefined;
21
+ const daysInMonth = month !== undefined && year !== undefined
22
+ ? new Date(Date.UTC(year, month, 0)).getUTCDate()
23
+ : 0;
24
+ const dateCells = daysInMonth > 0
25
+ ? [...document.querySelectorAll("div")]
26
+ .map((element) => {
27
+ const children = [...element.children];
28
+ for (let start = 0; start <= children.length - daysInMonth; start += 1) {
29
+ const candidate = children.slice(start, start + daysInMonth);
30
+ if (candidate.every((child, index) => {
31
+ const match = child.textContent?.trim().match(/(\d{1,2})$/);
32
+ return match !== null && Number(match[1]) === index + 1;
33
+ })) {
34
+ return candidate;
35
+ }
36
+ }
37
+ return undefined;
38
+ })
39
+ .find((candidate) => candidate !== undefined)
40
+ : undefined;
41
+ const dates = dateCells && month !== undefined && year !== undefined
42
+ ? dateCells.map((_, index) => {
43
+ const mm = String(month).padStart(2, "0");
44
+ const dd = String(index + 1).padStart(2, "0");
45
+ return `${year}-${mm}-${dd}`;
46
+ })
47
+ : [];
48
+ const taskInputs = [...document.querySelectorAll('input[name="task_name"]')];
49
+ const rows = taskInputs.flatMap((taskInput) => {
50
+ let row = taskInput.parentElement;
51
+ while (row &&
52
+ (row.querySelectorAll('input[name="task_name"]').length !== 1 ||
53
+ row.querySelectorAll('input[type="number"]').length === 0)) {
54
+ row = row.parentElement;
55
+ }
56
+ if (!row || daysInMonth === 0)
57
+ return [];
58
+ const durationContainer = [...row.querySelectorAll("div")].find((element) => {
59
+ const children = [...element.children];
60
+ return (children.length === daysInMonth + 1 &&
61
+ children
62
+ .slice(1)
63
+ .some((child) => child.querySelector('input[type="number"]')));
64
+ });
65
+ if (!durationContainer)
66
+ return [];
67
+ const project = row
68
+ .querySelector('[class$="-singleValue"], [class*="-singleValue "]')
69
+ ?.textContent?.trim();
70
+ const identityAttributes = [
71
+ "data-source-id",
72
+ "data-activity-id",
73
+ "data-task-id",
74
+ "data-row-id",
75
+ ];
76
+ const identityElements = [taskInput, row];
77
+ let sourceId;
78
+ for (const element of identityElements) {
79
+ for (const attribute of identityAttributes) {
80
+ const value = element.getAttribute(attribute)?.trim();
81
+ if (value) {
82
+ sourceId = `${attribute}:${value}`;
83
+ break;
84
+ }
85
+ }
86
+ if (sourceId)
87
+ break;
88
+ }
89
+ const durations = [...durationContainer.children].slice(1).map((cell) => cell.querySelector('input[type="number"]')?.value ?? "");
90
+ return [
91
+ {
92
+ ...(project ? { project } : {}),
93
+ description: taskInput.value,
94
+ ...(sourceId ? { sourceId } : {}),
95
+ durations,
96
+ },
97
+ ];
98
+ });
99
+ return {
100
+ titlePresent: document.title.trim().length > 0,
101
+ taskInputCount: taskInputs.length,
102
+ durationInputCount: document.querySelectorAll('input[type="number"]').length,
103
+ grid: { dates, rows },
104
+ };
105
+ });
106
+ if (contract.grid.dates.length === 0 ||
107
+ contract.grid.rows.some((row) => row.durations.length !== contract.grid.dates.length)) {
108
+ return undefined;
109
+ }
110
+ return {
111
+ urlOrigin: new URL(page.url()).origin,
112
+ ...contract,
113
+ };
114
+ }
115
+ //# sourceMappingURL=extract.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"extract.js","sourceRoot":"","sources":["../../../../../../../../packages/capabilities/jira/src/adapters/kawari/v1/extract.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,2 @@
1
+ import type { KawariScraper, TimesheetBrowserIO } from "../scraper.js";
2
+ export declare function createV1Scraper(timesheetUrl: string, io: TimesheetBrowserIO): KawariScraper;
@@ -0,0 +1,27 @@
1
+ import { assertV1Compatible } from "./detect.js";
2
+ import { waitForPageSignal } from "./ready.js";
3
+ import { selectTargetMonth } from "./navigation.js";
4
+ import { inspectReadyPage } from "./extract.js";
5
+ import { TimesheetBrowserError } from "../../../ports/timesheet.js";
6
+ export function createV1Scraper(timesheetUrl, io) {
7
+ return {
8
+ version: "v1",
9
+ label: "Kawari Timesheet v1",
10
+ assertCompatible: (page) => assertV1Compatible(page, timesheetUrl),
11
+ async waitForReady(page, signal) {
12
+ await waitForPageSignal(page, signal);
13
+ },
14
+ async navigateToMonth(page, target, signal) {
15
+ const targetMonth = `${target.year}-${String(target.month).padStart(2, "0")}`;
16
+ await selectTargetMonth(page, targetMonth, timesheetUrl, io, signal);
17
+ },
18
+ async extractGrid(page) {
19
+ const inspection = await inspectReadyPage(page, timesheetUrl);
20
+ if (!inspection) {
21
+ throw new TimesheetBrowserError("Could not read the Kawari Timesheet grid. The page may have changed or is in an unexpected state.");
22
+ }
23
+ return inspection.grid;
24
+ },
25
+ };
26
+ }
27
+ //# sourceMappingURL=index.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"index.js","sourceRoot":"","sources":["../../../../../../../../packages/capabilities/jira/src/adapters/kawari/v1/index.ts"],"names":[],"mappings":"AAEA,OAAO,EAAE,kBAAkB,EAAE,MAAM,aAAa,CAAC;AACjD,OAAO,EAAE,iBAAiB,EAAE,MAAM,YAAY,CAAC;AAC/C,OAAO,EAAE,iBAAiB,EAAE,MAAM,iBAAiB,CAAC;AACpD,OAAO,EAAE,gBAAgB,EAAE,MAAM,cAAc,CAAC;AAChD,OAAO,EAAE,qBAAqB,EAAE,MAAM,6BAA6B,CAAC;AAEpE,MAAM,UAAU,eAAe,CAC7B,YAAoB,EACpB,EAAsB;IAEtB,OAAO;QACL,OAAO,EAAE,IAAI;QACb,KAAK,EAAE,qBAAqB;QAE5B,gBAAgB,EAAE,CAAC,IAAI,EAAE,EAAE,CAAC,kBAAkB,CAAC,IAAI,EAAE,YAAY,CAAC;QAElE,KAAK,CAAC,YAAY,CAAC,IAAI,EAAE,MAAM;YAC7B,MAAM,iBAAiB,CAAC,IAAI,EAAE,MAAM,CAAC,CAAC;QACxC,CAAC;QAED,KAAK,CAAC,eAAe,CAAC,IAAI,EAAE,MAAM,EAAE,MAAM;YACxC,MAAM,WAAW,GAAG,GAAG,MAAM,CAAC,IAAI,IAAI,MAAM,CAAC,MAAM,CAAC,KAAK,CAAC,CAAC,QAAQ,CAAC,CAAC,EAAE,GAAG,CAAC,EAAE,CAAC;YAC9E,MAAM,iBAAiB,CAAC,IAAI,EAAE,WAAW,EAAE,YAAY,EAAE,EAAE,EAAE,MAAM,CAAC,CAAC;QACvE,CAAC;QAED,KAAK,CAAC,WAAW,CAAC,IAAI;YACpB,MAAM,UAAU,GAAG,MAAM,gBAAgB,CAAC,IAAI,EAAE,YAAY,CAAC,CAAC;YAC9D,IAAI,CAAC,UAAU,EAAE,CAAC;gBAChB,MAAM,IAAI,qBAAqB,CAC7B,mGAAmG,CACpG,CAAC;YACJ,CAAC;YACD,OAAO,UAAU,CAAC,IAAI,CAAC;QACzB,CAAC;KACF,CAAC;AACJ,CAAC"}
@@ -0,0 +1,3 @@
1
+ import type { Page } from "playwright";
2
+ import type { TimesheetBrowserIO } from "../scraper.js";
3
+ export declare function selectTargetMonth(page: Page, targetMonth: string, expectedUrl: string, io: TimesheetBrowserIO, signal: AbortSignal): Promise<void>;
@@ -0,0 +1,104 @@
1
+ import { inspectReadyPage } from "./extract.js";
2
+ import { waitForPageSignal } from "./ready.js";
3
+ import { TimesheetBrowserError } from "../../../ports/timesheet.js";
4
+ const MONTH_NAMES = [
5
+ "Jan", "Feb", "Mar", "Apr", "May", "Jun",
6
+ "Jul", "Aug", "Sep", "Oct", "Nov", "Dec",
7
+ ];
8
+ const MAX_MONTH_NAVIGATION_STEPS = 120;
9
+ function parseDisplayedMonth(value) {
10
+ const match = /^(Jan|Feb|Mar|Apr|May|Jun|Jul|Aug|Sep|Oct|Nov|Dec) (\d{4})$/.exec(value);
11
+ if (!match)
12
+ return undefined;
13
+ const month = MONTH_NAMES.indexOf(match[1]) + 1;
14
+ return `${match[2]}-${String(month).padStart(2, "0")}`;
15
+ }
16
+ function monthIndex(value) {
17
+ return Number(value.slice(0, 4)) * 12 + Number(value.slice(5, 7)) - 1;
18
+ }
19
+ async function displayedMonth(page) {
20
+ const text = await page.evaluate(() => {
21
+ const pattern = /^(Jan|Feb|Mar|Apr|May|Jun|Jul|Aug|Sep|Oct|Nov|Dec) \d{4}$/;
22
+ return [...document.querySelectorAll("body *")]
23
+ .map((element) => element.textContent?.trim() ?? "")
24
+ .find((candidate) => pattern.test(candidate));
25
+ });
26
+ return text ? parseDisplayedMonth(text) : undefined;
27
+ }
28
+ async function clickMonthNavigation(page, direction) {
29
+ return page.evaluate((requestedDirection) => {
30
+ const pattern = /^(Jan|Feb|Mar|Apr|May|Jun|Jul|Aug|Sep|Oct|Nov|Dec) \d{4}$/;
31
+ const labels = [...document.querySelectorAll("body *")]
32
+ .filter((element) => pattern.test(element.textContent?.trim() ?? ""));
33
+ for (const label of labels) {
34
+ let container = label.parentElement;
35
+ for (let depth = 0; container && depth < 6; depth += 1, container = container.parentElement) {
36
+ const buttons = [...container.querySelectorAll("button")];
37
+ const previous = buttons.find((button) => button.textContent?.trim() === "<");
38
+ const next = buttons.find((button) => button.textContent?.trim() === ">");
39
+ if (previous && next) {
40
+ (requestedDirection === "previous" ? previous : next).click();
41
+ return true;
42
+ }
43
+ }
44
+ }
45
+ return false;
46
+ }, direction);
47
+ }
48
+ export async function selectTargetMonth(page, targetMonth, expectedUrl, io, signal) {
49
+ signal.throwIfAborted();
50
+ let inspection = await inspectReadyPage(page, expectedUrl);
51
+ let currentMonth = inspection?.grid.dates[0]?.slice(0, 7) ?? await displayedMonth(page);
52
+ let automaticFailure = inspection === undefined || currentMonth === undefined;
53
+ for (let step = 0; !automaticFailure && currentMonth !== targetMonth; step += 1) {
54
+ if (step >= MAX_MONTH_NAVIGATION_STEPS) {
55
+ automaticFailure = true;
56
+ break;
57
+ }
58
+ const previousMonth = currentMonth;
59
+ const direction = previousMonth > targetMonth ? "previous" : "next";
60
+ try {
61
+ if (!await clickMonthNavigation(page, direction)) {
62
+ automaticFailure = true;
63
+ break;
64
+ }
65
+ await page.waitForFunction((month) => {
66
+ const pattern = /^(Jan|Feb|Mar|Apr|May|Jun|Jul|Aug|Sep|Oct|Nov|Dec) \d{4}$/;
67
+ return [...document.querySelectorAll("body *")]
68
+ .map((element) => element.textContent?.trim() ?? "")
69
+ .some((text) => pattern.test(text) && text !== month);
70
+ }, MONTH_NAMES[Number(previousMonth.slice(5, 7)) - 1] + ` ${previousMonth.slice(0, 4)}`, { timeout: 60_000, polling: 100 });
71
+ await waitForPageSignal(page, signal);
72
+ inspection = await inspectReadyPage(page, expectedUrl);
73
+ currentMonth = inspection?.grid.dates[0]?.slice(0, 7);
74
+ if (!inspection ||
75
+ !currentMonth ||
76
+ Math.abs(monthIndex(currentMonth) - monthIndex(targetMonth)) >=
77
+ Math.abs(monthIndex(previousMonth) - monthIndex(targetMonth))) {
78
+ automaticFailure = true;
79
+ }
80
+ }
81
+ catch {
82
+ if (signal.aborted) {
83
+ throw new TimesheetBrowserError("Kawari Timesheet did not finish loading within 60 seconds.");
84
+ }
85
+ automaticFailure = true;
86
+ }
87
+ }
88
+ if (!automaticFailure && inspection && currentMonth === targetMonth)
89
+ return;
90
+ try {
91
+ await io.waitForMonthSelection();
92
+ }
93
+ catch {
94
+ throw new TimesheetBrowserError("Manual month selection requires an interactive terminal.");
95
+ }
96
+ io.reportProgress?.({ stage: "selecting-month", targetMonth });
97
+ await waitForPageSignal(page, signal);
98
+ const manualInspection = await inspectReadyPage(page, expectedUrl);
99
+ const manualMonth = manualInspection?.grid.dates[0]?.slice(0, 7);
100
+ if (!manualInspection || manualMonth !== targetMonth) {
101
+ throw new TimesheetBrowserError(`Kawari Timesheet is showing ${manualMonth ?? "an unknown month"}; expected ${targetMonth}.`);
102
+ }
103
+ }
104
+ //# sourceMappingURL=navigation.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"navigation.js","sourceRoot":"","sources":["../../../../../../../../packages/capabilities/jira/src/adapters/kawari/v1/navigation.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,2 @@
1
+ import type { Page } from "playwright";
2
+ export declare function waitForPageSignal(page: Page, signal: AbortSignal): Promise<void>;
@@ -0,0 +1,47 @@
1
+ import { TimesheetBrowserError } from "../../../ports/timesheet.js";
2
+ const TIMESHEET_READY_TIMEOUT_MS = 60_000;
3
+ export async function waitForPageSignal(page, signal) {
4
+ signal.throwIfAborted();
5
+ try {
6
+ await page.waitForFunction(() => {
7
+ const loader = [...document.querySelectorAll('[class*="-Loader"]')].some((element) => {
8
+ const style = getComputedStyle(element);
9
+ return style.display !== "none" && style.visibility !== "hidden";
10
+ });
11
+ if (loader)
12
+ return false;
13
+ const monthNames = [
14
+ "Jan", "Feb", "Mar", "Apr", "May", "Jun",
15
+ "Jul", "Aug", "Sep", "Oct", "Nov", "Dec",
16
+ ];
17
+ const monthPattern = /^(Jan|Feb|Mar|Apr|May|Jun|Jul|Aug|Sep|Oct|Nov|Dec) (\d{4})$/;
18
+ const heading = [...document.querySelectorAll("body *")]
19
+ .map((element) => element.textContent?.trim() ?? "")
20
+ .find((text) => monthPattern.test(text));
21
+ const match = heading?.match(monthPattern);
22
+ if (!match)
23
+ return false;
24
+ const month = monthNames.indexOf(match[1]) + 1;
25
+ const year = Number(match[2]);
26
+ const daysInMonth = new Date(Date.UTC(year, month, 0)).getUTCDate();
27
+ return [...document.querySelectorAll("div")].some((element) => {
28
+ const children = [...element.children];
29
+ for (let start = 0; start <= children.length - daysInMonth; start += 1) {
30
+ const candidate = children.slice(start, start + daysInMonth);
31
+ if (candidate.every((child, index) => {
32
+ const day = child.textContent?.trim().match(/(\d{1,2})$/);
33
+ return day !== null && Number(day[1]) === index + 1;
34
+ })) {
35
+ return true;
36
+ }
37
+ }
38
+ return false;
39
+ });
40
+ }, undefined, { timeout: TIMESHEET_READY_TIMEOUT_MS, polling: 100 });
41
+ signal.throwIfAborted();
42
+ }
43
+ catch {
44
+ throw new TimesheetBrowserError("Kawari Timesheet did not finish loading within 60 seconds.");
45
+ }
46
+ }
47
+ //# sourceMappingURL=ready.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"ready.js","sourceRoot":"","sources":["../../../../../../../../packages/capabilities/jira/src/adapters/kawari/v1/ready.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,4 @@
1
+ export declare const LOGIN_PROMPT = "Kawari login is required. Complete login in the browser, then press Enter here to continue.\n";
2
+ export declare const MONTH_SELECTION_PROMPT: (targetMonth: string) => string;
3
+ export declare const TIMESHEET_READY_TIMEOUT_MS = 60000;
4
+ export declare const MAX_MONTH_NAVIGATION_STEPS = 120;