@monotykamary/localterm-server 1.17.1 → 1.18.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 (53) hide show
  1. package/dist/automation-scheduler.d.ts.map +1 -1
  2. package/dist/automation-scheduler.js +8 -2
  3. package/dist/automation-scheduler.js.map +1 -1
  4. package/dist/automation-store.d.ts +5 -2
  5. package/dist/automation-store.d.ts.map +1 -1
  6. package/dist/automation-store.js +125 -13
  7. package/dist/automation-store.js.map +1 -1
  8. package/dist/cdp/cdp-client.d.ts +59 -0
  9. package/dist/cdp/cdp-client.d.ts.map +1 -0
  10. package/dist/cdp/cdp-client.js +207 -0
  11. package/dist/cdp/cdp-client.js.map +1 -0
  12. package/dist/cdp/detect-chromium.d.ts +38 -0
  13. package/dist/cdp/detect-chromium.d.ts.map +1 -0
  14. package/dist/cdp/detect-chromium.js +97 -0
  15. package/dist/cdp/detect-chromium.js.map +1 -0
  16. package/dist/cdp/open-background-tab.d.ts +33 -0
  17. package/dist/cdp/open-background-tab.d.ts.map +1 -0
  18. package/dist/cdp/open-background-tab.js +98 -0
  19. package/dist/cdp/open-background-tab.js.map +1 -0
  20. package/dist/constants.d.ts +8 -1
  21. package/dist/constants.d.ts.map +1 -1
  22. package/dist/constants.js +26 -1
  23. package/dist/constants.js.map +1 -1
  24. package/dist/heartbeat-store.d.ts +7 -0
  25. package/dist/heartbeat-store.d.ts.map +1 -0
  26. package/dist/heartbeat-store.js +45 -0
  27. package/dist/heartbeat-store.js.map +1 -0
  28. package/dist/index.d.ts +6 -0
  29. package/dist/index.d.ts.map +1 -1
  30. package/dist/index.js +155 -21
  31. package/dist/index.js.map +1 -1
  32. package/dist/protocol.d.ts +4 -3
  33. package/dist/protocol.d.ts.map +1 -1
  34. package/dist/protocol.js +3 -2
  35. package/dist/protocol.js.map +1 -1
  36. package/dist/schemas.d.ts +626 -16
  37. package/dist/schemas.d.ts.map +1 -1
  38. package/dist/schemas.js +179 -14
  39. package/dist/schemas.js.map +1 -1
  40. package/dist/types.d.ts +8 -1
  41. package/dist/types.d.ts.map +1 -1
  42. package/dist/utils/compile-schedule.d.ts +6 -0
  43. package/dist/utils/compile-schedule.d.ts.map +1 -0
  44. package/dist/utils/compile-schedule.js +173 -0
  45. package/dist/utils/compile-schedule.js.map +1 -0
  46. package/dist/utils/compute-next-automation-run-at.d.ts.map +1 -1
  47. package/dist/utils/compute-next-automation-run-at.js +14 -3
  48. package/dist/utils/compute-next-automation-run-at.js.map +1 -1
  49. package/dist/utils/reconcile-downtime.d.ts +3 -0
  50. package/dist/utils/reconcile-downtime.d.ts.map +1 -0
  51. package/dist/utils/reconcile-downtime.js +25 -0
  52. package/dist/utils/reconcile-downtime.js.map +1 -0
  53. package/package.json +1 -1
@@ -0,0 +1,97 @@
1
+ /**
2
+ * Detect Chromium-based browsers that currently have remote debugging enabled.
3
+ *
4
+ * A browser writes a `DevToolsActivePort` file into its user-data dir while a
5
+ * debug endpoint is live (the user toggled "Discover network targets" in
6
+ * chrome://inspect, or launched with --remote-debugging-port). The file holds
7
+ * the port on line 1 and the browser-level WebSocket path on line 2, which is
8
+ * everything we need to open a CDP connection — no HTTP probe required.
9
+ *
10
+ * Ported from the browser-harness-js CDP SDK (Bun) to dependency-free Node.
11
+ */
12
+ import { promises as fs } from "node:fs";
13
+ import os from "node:os";
14
+ import path from "node:path";
15
+ /** OS-specific user-data dirs for Chromium-based browsers, rough popularity order. */
16
+ export function getBrowserCandidates(home = os.homedir(), platform = process.platform) {
17
+ const list = [];
18
+ const push = (name, profileDir) => list.push({ name, profileDir });
19
+ if (platform === "darwin") {
20
+ const base = `${home}/Library/Application Support`;
21
+ push("Dia", `${base}/Dia/User Data`);
22
+ push("Google Chrome", `${base}/Google/Chrome`);
23
+ push("Chromium", `${base}/Chromium`);
24
+ push("Microsoft Edge", `${base}/Microsoft Edge`);
25
+ push("Brave", `${base}/BraveSoftware/Brave-Browser`);
26
+ push("Arc", `${base}/Arc/User Data`);
27
+ push("Vivaldi", `${base}/Vivaldi`);
28
+ push("Opera", `${base}/com.operasoftware.Opera`);
29
+ push("Comet", `${base}/Comet`);
30
+ push("Google Chrome Canary", `${base}/Google/Chrome Canary`);
31
+ }
32
+ else if (platform === "linux") {
33
+ const cfg = `${home}/.config`;
34
+ push("Dia", `${cfg}/dia`);
35
+ push("Google Chrome", `${cfg}/google-chrome`);
36
+ push("Chromium", `${cfg}/chromium`);
37
+ push("Microsoft Edge", `${cfg}/microsoft-edge`);
38
+ push("Brave", `${cfg}/BraveSoftware/Brave-Browser`);
39
+ push("Vivaldi", `${cfg}/vivaldi`);
40
+ push("Opera", `${cfg}/opera`);
41
+ push("Google Chrome Canary", `${cfg}/google-chrome-unstable`);
42
+ }
43
+ else if (platform === "win32") {
44
+ const local = process.env.LOCALAPPDATA ?? `${home}\\AppData\\Local`;
45
+ push("Dia", `${local}\\Dia\\User Data`);
46
+ push("Google Chrome", `${local}\\Google\\Chrome\\User Data`);
47
+ push("Chromium", `${local}\\Chromium\\User Data`);
48
+ push("Microsoft Edge", `${local}\\Microsoft\\Edge\\User Data`);
49
+ push("Brave", `${local}\\BraveSoftware\\Brave-Browser\\User Data`);
50
+ push("Arc", `${local}\\Arc\\User Data`);
51
+ push("Vivaldi", `${local}\\Vivaldi\\User Data`);
52
+ push("Opera", `${local}\\Opera Software\\Opera Stable`);
53
+ push("Google Chrome Canary", `${local}\\Google\\Chrome SxS\\User Data`);
54
+ }
55
+ return list;
56
+ }
57
+ /** Parse `<profileDir>/DevToolsActivePort`; undefined if missing/malformed. */
58
+ async function tryReadDevToolsActivePort(profileDir) {
59
+ const file = path.join(profileDir, "DevToolsActivePort");
60
+ try {
61
+ const [text, stat] = await Promise.all([fs.readFile(file, "utf8"), fs.stat(file)]);
62
+ const [portStr, wsPath] = text.trim().split("\n");
63
+ const port = Number(portStr);
64
+ if (!Number.isFinite(port))
65
+ return undefined;
66
+ if (!wsPath || !wsPath.startsWith("/devtools/"))
67
+ return undefined;
68
+ return { port, wsPath, mtimeMs: stat.mtimeMs };
69
+ }
70
+ catch {
71
+ return undefined;
72
+ }
73
+ }
74
+ /**
75
+ * Scan known user-data dirs and return every Chromium browser with a live
76
+ * DevToolsActivePort, most-recently-launched first. Does NOT verify the WS
77
+ * endpoint actually accepts — the caller does that by trying to connect.
78
+ */
79
+ export async function detectChromiumBrowsers(candidates = getBrowserCandidates()) {
80
+ const detected = [];
81
+ for (const { name, profileDir } of candidates) {
82
+ const parsed = await tryReadDevToolsActivePort(profileDir);
83
+ if (!parsed)
84
+ continue;
85
+ detected.push({
86
+ name,
87
+ profileDir,
88
+ port: parsed.port,
89
+ wsPath: parsed.wsPath,
90
+ wsUrl: `ws://127.0.0.1:${parsed.port}${parsed.wsPath}`,
91
+ mtimeMs: parsed.mtimeMs,
92
+ });
93
+ }
94
+ detected.sort((a, b) => b.mtimeMs - a.mtimeMs);
95
+ return detected;
96
+ }
97
+ //# sourceMappingURL=detect-chromium.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"detect-chromium.js","sourceRoot":"","sources":["../../src/cdp/detect-chromium.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,33 @@
1
+ /**
2
+ * Open a URL in a true background browser tab via the Chrome DevTools Protocol.
3
+ *
4
+ * Unlike the OS opener (which foregrounds the browser) or page-level
5
+ * `window.open` (which the browser forces to the front, or popup-blocks), CDP's
6
+ * `Target.createTarget` creates a tab that stays *behind* the active one unless
7
+ * you also call `Target.activateTarget`. We never activate it, so an automation
8
+ * firing never steals the user's focus.
9
+ *
10
+ * This only works when a Chromium-based browser is running with remote
11
+ * debugging enabled (see detect-chromium.ts). When none is found — or the
12
+ * browser refuses the connection — the caller falls back to the OS opener.
13
+ */
14
+ import { type DetectedBrowser } from "./detect-chromium.js";
15
+ /**
16
+ * Open one browser-level CDP WebSocket, ask it to create a background tab at
17
+ * `url`, and resolve the new target id. Rejects on timeout, socket error, or a
18
+ * CDP error reply. The socket is always closed before settling.
19
+ */
20
+ export declare function createBackgroundTab(wsUrl: string, url: string, timeoutMs?: number): Promise<string>;
21
+ export type OpenBackgroundTabOptions = {
22
+ /** Override browser detection (tests). Defaults to detectChromiumBrowsers. */
23
+ detect?: () => Promise<DetectedBrowser[]>;
24
+ /** Per-browser CDP attempt timeout. */
25
+ timeoutMs?: number;
26
+ };
27
+ /**
28
+ * Try to open `url` as a background tab in a debug-enabled Chromium browser.
29
+ * Returns the browser it used on success, or null when no browser accepted —
30
+ * the signal for the caller to fall back to the OS opener. Never throws.
31
+ */
32
+ export declare function openBackgroundTabViaCdp(url: string, options?: OpenBackgroundTabOptions): Promise<DetectedBrowser | null>;
33
+ //# sourceMappingURL=open-background-tab.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"open-background-tab.d.ts","sourceRoot":"","sources":["../../src/cdp/open-background-tab.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;GAYG;AAEH,OAAO,EAA0B,KAAK,eAAe,EAAE,MAAM,sBAAsB,CAAC;AAKpF;;;;GAIG;AACH,wBAAgB,mBAAmB,CACjC,KAAK,EAAE,MAAM,EACb,GAAG,EAAE,MAAM,EACX,SAAS,GAAE,MAA4B,GACtC,OAAO,CAAC,MAAM,CAAC,CA0CjB;AAED,MAAM,MAAM,wBAAwB,GAAG;IACrC,8EAA8E;IAC9E,MAAM,CAAC,EAAE,MAAM,OAAO,CAAC,eAAe,EAAE,CAAC,CAAC;IAC1C,uCAAuC;IACvC,SAAS,CAAC,EAAE,MAAM,CAAC;CACpB,CAAC;AAEF;;;;GAIG;AACH,wBAAsB,uBAAuB,CAC3C,GAAG,EAAE,MAAM,EACX,OAAO,GAAE,wBAA6B,GACrC,OAAO,CAAC,eAAe,GAAG,IAAI,CAAC,CAkBjC"}
@@ -0,0 +1,98 @@
1
+ /**
2
+ * Open a URL in a true background browser tab via the Chrome DevTools Protocol.
3
+ *
4
+ * Unlike the OS opener (which foregrounds the browser) or page-level
5
+ * `window.open` (which the browser forces to the front, or popup-blocks), CDP's
6
+ * `Target.createTarget` creates a tab that stays *behind* the active one unless
7
+ * you also call `Target.activateTarget`. We never activate it, so an automation
8
+ * firing never steals the user's focus.
9
+ *
10
+ * This only works when a Chromium-based browser is running with remote
11
+ * debugging enabled (see detect-chromium.ts). When none is found — or the
12
+ * browser refuses the connection — the caller falls back to the OS opener.
13
+ */
14
+ import { detectChromiumBrowsers } from "./detect-chromium.js";
15
+ /** Per-browser CDP attempt budget. A live endpoint replies in ~100ms. */
16
+ const CDP_CALL_TIMEOUT_MS = 2_000;
17
+ /**
18
+ * Open one browser-level CDP WebSocket, ask it to create a background tab at
19
+ * `url`, and resolve the new target id. Rejects on timeout, socket error, or a
20
+ * CDP error reply. The socket is always closed before settling.
21
+ */
22
+ export function createBackgroundTab(wsUrl, url, timeoutMs = CDP_CALL_TIMEOUT_MS) {
23
+ return new Promise((resolve, reject) => {
24
+ const ws = new WebSocket(wsUrl);
25
+ let settled = false;
26
+ const finish = (error, targetId) => {
27
+ if (settled)
28
+ return;
29
+ settled = true;
30
+ clearTimeout(timer);
31
+ try {
32
+ ws.close();
33
+ }
34
+ catch {
35
+ /* already closing */
36
+ }
37
+ if (error)
38
+ reject(error);
39
+ else
40
+ resolve(targetId);
41
+ };
42
+ const timer = setTimeout(() => finish(new Error(`CDP timed out after ${timeoutMs}ms`)), timeoutMs);
43
+ ws.addEventListener("open", () => {
44
+ // `Target.createTarget` is browser-level (no sessionId). Omitting
45
+ // `background`/`newWindow` opens a new tab behind the active one.
46
+ ws.send(JSON.stringify({ id: 1, method: "Target.createTarget", params: { url } }));
47
+ });
48
+ ws.addEventListener("message", (event) => {
49
+ let message;
50
+ try {
51
+ message = JSON.parse(String(event.data));
52
+ }
53
+ catch {
54
+ return;
55
+ }
56
+ if (message.id !== 1)
57
+ return;
58
+ if (message.error) {
59
+ finish(new Error(`CDP error: ${message.error.message ?? "unknown"}`));
60
+ return;
61
+ }
62
+ const targetId = message.result?.targetId;
63
+ if (typeof targetId === "string")
64
+ finish(undefined, targetId);
65
+ else
66
+ finish(new Error("CDP createTarget returned no targetId"));
67
+ });
68
+ ws.addEventListener("error", () => finish(new Error("CDP websocket error")));
69
+ ws.addEventListener("close", () => finish(new Error("CDP websocket closed before reply")));
70
+ });
71
+ }
72
+ /**
73
+ * Try to open `url` as a background tab in a debug-enabled Chromium browser.
74
+ * Returns the browser it used on success, or null when no browser accepted —
75
+ * the signal for the caller to fall back to the OS opener. Never throws.
76
+ */
77
+ export async function openBackgroundTabViaCdp(url, options = {}) {
78
+ const detect = options.detect ?? detectChromiumBrowsers;
79
+ let browsers;
80
+ try {
81
+ browsers = await detect();
82
+ }
83
+ catch {
84
+ return null;
85
+ }
86
+ for (const browser of browsers) {
87
+ try {
88
+ await createBackgroundTab(browser.wsUrl, url, options.timeoutMs);
89
+ return browser;
90
+ }
91
+ catch {
92
+ // Dead port, 403 (permission not granted), or a forked browser that
93
+ // refused — move on to the next detected browser.
94
+ }
95
+ }
96
+ return null;
97
+ }
98
+ //# sourceMappingURL=open-background-tab.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"open-background-tab.js","sourceRoot":"","sources":["../../src/cdp/open-background-tab.ts"],"names":[],"mappings":"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"}
@@ -55,7 +55,14 @@ export declare const MAX_AUTOMATIONS = 100;
55
55
  export declare const MAX_AUTOMATION_NAME_LENGTH = 120;
56
56
  export declare const MAX_AUTOMATION_COMMAND_LENGTH = 4096;
57
57
  export declare const MAX_CRON_EXPRESSION_LENGTH = 256;
58
- export declare const AUTOMATIONS_FILE_VERSION = 1;
58
+ export declare const AUTOMATIONS_FILE_VERSION = 2;
59
+ export declare const AUTOMATION_RUN_LIMIT_MAX = 100000;
60
+ export declare const AUTOMATION_RUN_HISTORY_CAP = 50;
61
+ export declare const AUTOMATION_DOWNTIME_RECONCILE_CAP = 10;
62
+ export declare const MAX_AUTOMATION_TIMES_PER_DAY = 12;
63
+ export declare const AUTOMATION_RECONCILE_MIN_DOWNTIME_MS = 90000;
64
+ export declare const AUTOMATION_RECONCILE_LOOKBACK_MS: number;
65
+ export declare const DAEMON_HEARTBEAT_FILE_VERSION = 1;
59
66
  export declare const AUTOMATION_TICK_ALIGNMENT_DELAY_MS = 50;
60
67
  export declare const AUTOMATION_PENDING_RUN_EXPIRY_MS: number;
61
68
  export declare const CRON_NEXT_OCCURRENCE_SCAN_LIMIT_DAYS = 1466;
@@ -1 +1 @@
1
- {"version":3,"file":"constants.d.ts","sourceRoot":"","sources":["../src/constants.ts"],"names":[],"mappings":"AAAA,eAAO,MAAM,YAAY,OAAO,CAAC;AACjC,eAAO,MAAM,YAAY,cAAc,CAAC;AACxC,eAAO,MAAM,iBAAiB,wBAAwB,CAAC;AACvD,eAAO,MAAM,YAAY,MAAM,CAAC;AAChC,eAAO,MAAM,YAAY,KAAK,CAAC;AAC/B,eAAO,MAAM,sBAAsB,YAAY,CAAC;AAEhD,eAAO,MAAM,SAAS,mBAAmB,CAAC;AAC1C,eAAO,MAAM,eAAe,cAAc,CAAC;AAC3C,eAAO,MAAM,eAAe,MAAM,CAAC;AAEnC,eAAO,MAAM,uBAAuB,IAAI,CAAC;AAEzC;;;;;;;;GAQG;AACH,eAAO,MAAM,gBAAgB,UAgB5B,CAAC;AAEF,eAAO,MAAM,eAAe,QAAY,CAAC;AACzC,eAAO,MAAM,gBAAgB,QAAkB,CAAC;AAChD,eAAO,MAAM,qBAAqB,MAAM,CAAC;AACzC,eAAO,MAAM,gBAAgB,QAAW,CAAC;AACzC,eAAO,MAAM,uBAAuB,OAAO,CAAC;AAC5C,eAAO,MAAM,uBAAuB,OAAO,CAAC;AAC5C,eAAO,MAAM,QAAQ,OAAO,CAAC;AAC7B,eAAO,MAAM,QAAQ,OAAO,CAAC;AAC7B,eAAO,MAAM,uBAAuB,KAAK,CAAC;AAO1C,eAAO,MAAM,kCAAkC,QAAkB,CAAC;AAClE,eAAO,MAAM,kCAAkC,QAAkB,CAAC;AAClE,eAAO,MAAM,yBAAyB,KAAK,CAAC;AAC5C,eAAO,MAAM,+BAA+B,QAAmB,CAAC;AAUhE,eAAO,MAAM,wBAAwB,QAAW,CAAC;AAajD,eAAO,MAAM,sBAAsB,IAAI,CAAC;AAOxC,eAAO,MAAM,wBAAwB,QAAS,CAAC;AAC/C,eAAO,MAAM,uBAAuB,QAAS,CAAC;AAC9C,eAAO,MAAM,2BAA2B,MAAM,CAAC;AAK/C,eAAO,MAAM,oBAAoB,OAAQ,CAAC;AAE1C,eAAO,MAAM,cAAc,aAAoE,CAAC;AAEhG,eAAO,MAAM,qBAAqB,MAAM,CAAC;AACzC,eAAO,MAAM,uBAAuB,MAAM,CAAC;AAM3C,eAAO,MAAM,sBAAsB,QAAS,CAAC;AAI7C,eAAO,MAAM,oBAAoB,QAAmB,CAAC;AAGrD,eAAO,MAAM,mBAAmB,6CAA6C,CAAC;AAK9E,eAAO,MAAM,uBAAuB,MAAM,CAAC;AAC3C,eAAO,MAAM,4BAA4B,QAAkB,CAAC;AAG5D,eAAO,MAAM,sBAAsB,OAAO,CAAC;AAI3C,eAAO,MAAM,4BAA4B,QAAkB,CAAC;AAC5D,eAAO,MAAM,yBAAyB,QAAmB,CAAC;AAC1D,eAAO,MAAM,qBAAqB,MAAM,CAAC;AAEzC,eAAO,MAAM,mBAAmB,MAAM,CAAC;AAEvC,eAAO,MAAM,aAAa,QAAS,CAAC;AAEpC,eAAO,MAAM,eAAe,MAAM,CAAC;AACnC,eAAO,MAAM,0BAA0B,MAAM,CAAC;AAC9C,eAAO,MAAM,6BAA6B,OAAO,CAAC;AAClD,eAAO,MAAM,0BAA0B,MAAM,CAAC;AAC9C,eAAO,MAAM,wBAAwB,IAAI,CAAC;AAG1C,eAAO,MAAM,kCAAkC,KAAK,CAAC;AAGrD,eAAO,MAAM,gCAAgC,QAAgB,CAAC;AAE9D,eAAO,MAAM,oCAAoC,OAAO,CAAC;AACzD,eAAO,MAAM,+BAA+B,IAAI,CAAC;AAEjD,eAAO,MAAM,mBAAmB,IAAI,CAAC;AACrC,eAAO,MAAM,yBAAyB,OAAO,CAAC;AAC9C,eAAO,MAAM,qBAAqB,OAAO,CAAC;AAC1C,eAAO,MAAM,yBAAyB,OAAO,CAAC"}
1
+ {"version":3,"file":"constants.d.ts","sourceRoot":"","sources":["../src/constants.ts"],"names":[],"mappings":"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"}
package/dist/constants.js CHANGED
@@ -123,7 +123,32 @@ export const MAX_AUTOMATIONS = 100;
123
123
  export const MAX_AUTOMATION_NAME_LENGTH = 120;
124
124
  export const MAX_AUTOMATION_COMMAND_LENGTH = 4096;
125
125
  export const MAX_CRON_EXPRESSION_LENGTH = 256;
126
- export const AUTOMATIONS_FILE_VERSION = 1;
126
+ // v1 stored a raw cron string + a single lastRun. v2 stores a structured
127
+ // schedule (with a derived cron computed on the fly), a run-count limit, a
128
+ // lifecycle, and a capped run-history array. AutomationStore.load() migrates
129
+ // v1 -> v2 in place on first boot so existing automations are never lost.
130
+ export const AUTOMATIONS_FILE_VERSION = 2;
131
+ // Largest "stop after N runs" budget. Generous — a limit is opt-in; the common
132
+ // case is "forever".
133
+ export const AUTOMATION_RUN_LIMIT_MAX = 100_000;
134
+ // Per-automation run-history ring. Newest-first; appendRun trims to this. At
135
+ // MAX_AUTOMATIONS the whole history file stays around 1 MB in the worst case.
136
+ export const AUTOMATION_RUN_HISTORY_CAP = 50;
137
+ // Most-recent "skipped" entries reconstructed per automation per outage. A
138
+ // frequent schedule (every minute) over a multi-day sleep would otherwise
139
+ // record thousands of skips and evict every real run from the ring.
140
+ export const AUTOMATION_DOWNTIME_RECONCILE_CAP = 10;
141
+ // A "multiple times a day" schedule compiles to one cron per distinct time.
142
+ export const MAX_AUTOMATION_TIMES_PER_DAY = 12;
143
+ // Downtime shorter than this is treated as a clean restart (no reconciliation):
144
+ // the daemon writes its heartbeat ~once a minute, so a same-minute bounce must
145
+ // not manufacture "skipped" entries.
146
+ export const AUTOMATION_RECONCILE_MIN_DOWNTIME_MS = 90_000;
147
+ // Cap how far back startup reconciliation enumerates missed occurrences. Bounds
148
+ // the work for a frequent (every-minute) schedule after a long outage; we keep
149
+ // only the most-recent AUTOMATION_DOWNTIME_RECONCILE_CAP per automation anyway.
150
+ export const AUTOMATION_RECONCILE_LOOKBACK_MS = 14 * 24 * 60 * 60 * 1000;
151
+ export const DAEMON_HEARTBEAT_FILE_VERSION = 1;
127
152
  // Ticks land just past the minute boundary so a timer that fires marginally
128
153
  // early can never evaluate the previous minute twice.
129
154
  export const AUTOMATION_TICK_ALIGNMENT_DELAY_MS = 50;
@@ -1 +1 @@
1
- {"version":3,"file":"constants.js","sourceRoot":"","sources":["../src/constants.ts"],"names":[],"mappings":"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"}
1
+ {"version":3,"file":"constants.js","sourceRoot":"","sources":["../src/constants.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,7 @@
1
+ export declare class HeartbeatStore {
2
+ private readonly filePath;
3
+ constructor(filePath: string);
4
+ read(): number | null;
5
+ write(lastAliveAt: number): void;
6
+ }
7
+ //# sourceMappingURL=heartbeat-store.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"heartbeat-store.d.ts","sourceRoot":"","sources":["../src/heartbeat-store.ts"],"names":[],"mappings":"AAiBA,qBAAa,cAAc;IACb,OAAO,CAAC,QAAQ,CAAC,QAAQ;gBAAR,QAAQ,EAAE,MAAM;IAE7C,IAAI,IAAI,MAAM,GAAG,IAAI;IAerB,KAAK,CAAC,WAAW,EAAE,MAAM,GAAG,IAAI;CAOjC"}
@@ -0,0 +1,45 @@
1
+ import fs from "node:fs";
2
+ import path from "node:path";
3
+ import { z } from "zod";
4
+ import { DAEMON_HEARTBEAT_FILE_VERSION } from "./constants.js";
5
+ // A tiny sibling of automations.json (~/.localterm/daemon-heartbeat.json). The
6
+ // scheduler stamps `lastAliveAt` here every minute; on the next boot the gap
7
+ // between this timestamp and "now" is the downtime window used to reconstruct
8
+ // "skipped" runs. It lives in its own file so the per-minute write never
9
+ // rewrites (or races) the much larger automations history file.
10
+ const heartbeatFileSchema = z
11
+ .object({
12
+ version: z.literal(DAEMON_HEARTBEAT_FILE_VERSION),
13
+ lastAliveAt: z.number().int().nonnegative(),
14
+ })
15
+ .strict();
16
+ export class HeartbeatStore {
17
+ filePath;
18
+ constructor(filePath) {
19
+ this.filePath = filePath;
20
+ }
21
+ read() {
22
+ let raw;
23
+ try {
24
+ raw = fs.readFileSync(this.filePath, "utf8");
25
+ }
26
+ catch {
27
+ return null;
28
+ }
29
+ try {
30
+ const parsed = heartbeatFileSchema.safeParse(JSON.parse(raw));
31
+ return parsed.success ? parsed.data.lastAliveAt : null;
32
+ }
33
+ catch {
34
+ return null;
35
+ }
36
+ }
37
+ write(lastAliveAt) {
38
+ fs.mkdirSync(path.dirname(this.filePath), { recursive: true });
39
+ const payload = { version: DAEMON_HEARTBEAT_FILE_VERSION, lastAliveAt };
40
+ const tmpPath = `${this.filePath}.tmp`;
41
+ fs.writeFileSync(tmpPath, `${JSON.stringify(payload)}\n`, "utf8");
42
+ fs.renameSync(tmpPath, this.filePath);
43
+ }
44
+ }
45
+ //# sourceMappingURL=heartbeat-store.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"heartbeat-store.js","sourceRoot":"","sources":["../src/heartbeat-store.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,MAAM,SAAS,CAAC;AACzB,OAAO,IAAI,MAAM,WAAW,CAAC;AAC7B,OAAO,EAAE,CAAC,EAAE,MAAM,KAAK,CAAC;AACxB,OAAO,EAAE,6BAA6B,EAAE,MAAM,gBAAgB,CAAC;AAE/D,+EAA+E;AAC/E,6EAA6E;AAC7E,8EAA8E;AAC9E,yEAAyE;AACzE,gEAAgE;AAChE,MAAM,mBAAmB,GAAG,CAAC;KAC1B,MAAM,CAAC;IACN,OAAO,EAAE,CAAC,CAAC,OAAO,CAAC,6BAA6B,CAAC;IACjD,WAAW,EAAE,CAAC,CAAC,MAAM,EAAE,CAAC,GAAG,EAAE,CAAC,WAAW,EAAE;CAC5C,CAAC;KACD,MAAM,EAAE,CAAC;AAEZ,MAAM,OAAO,cAAc;IACI;IAA7B,YAA6B,QAAgB;QAAhB,aAAQ,GAAR,QAAQ,CAAQ;IAAG,CAAC;IAEjD,IAAI;QACF,IAAI,GAAW,CAAC;QAChB,IAAI,CAAC;YACH,GAAG,GAAG,EAAE,CAAC,YAAY,CAAC,IAAI,CAAC,QAAQ,EAAE,MAAM,CAAC,CAAC;QAC/C,CAAC;QAAC,MAAM,CAAC;YACP,OAAO,IAAI,CAAC;QACd,CAAC;QACD,IAAI,CAAC;YACH,MAAM,MAAM,GAAG,mBAAmB,CAAC,SAAS,CAAC,IAAI,CAAC,KAAK,CAAC,GAAG,CAAC,CAAC,CAAC;YAC9D,OAAO,MAAM,CAAC,OAAO,CAAC,CAAC,CAAC,MAAM,CAAC,IAAI,CAAC,WAAW,CAAC,CAAC,CAAC,IAAI,CAAC;QACzD,CAAC;QAAC,MAAM,CAAC;YACP,OAAO,IAAI,CAAC;QACd,CAAC;IACH,CAAC;IAED,KAAK,CAAC,WAAmB;QACvB,EAAE,CAAC,SAAS,CAAC,IAAI,CAAC,OAAO,CAAC,IAAI,CAAC,QAAQ,CAAC,EAAE,EAAE,SAAS,EAAE,IAAI,EAAE,CAAC,CAAC;QAC/D,MAAM,OAAO,GAAG,EAAE,OAAO,EAAE,6BAA6B,EAAE,WAAW,EAAE,CAAC;QACxE,MAAM,OAAO,GAAG,GAAG,IAAI,CAAC,QAAQ,MAAM,CAAC;QACvC,EAAE,CAAC,aAAa,CAAC,OAAO,EAAE,GAAG,IAAI,CAAC,SAAS,CAAC,OAAO,CAAC,IAAI,EAAE,MAAM,CAAC,CAAC;QAClE,EAAE,CAAC,UAAU,CAAC,OAAO,EAAE,IAAI,CAAC,QAAQ,CAAC,CAAC;IACxC,CAAC;CACF"}
package/dist/index.d.ts CHANGED
@@ -4,6 +4,12 @@ export interface ServerOptions {
4
4
  host?: string;
5
5
  staticRoot?: string | null;
6
6
  stateDirectory?: string;
7
+ /**
8
+ * Override how automation run URLs are opened. When provided, the caller owns
9
+ * tab-opening and the built-in CDP background-tab path is disabled. Defaults
10
+ * to: CDP background tab when a debug-enabled Chromium browser is reachable,
11
+ * else the OS opener (`open -g`).
12
+ */
7
13
  openUrl?: (url: string) => Promise<void>;
8
14
  }
9
15
  export interface RunningServer {
@@ -1 +1 @@
1
- {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AA4CA,OAAO,EAAE,eAAe,EAAE,MAAM,uBAAuB,CAAC;AAKxD,MAAM,WAAW,aAAa;IAC5B,IAAI,CAAC,EAAE,MAAM,CAAC;IACd,IAAI,CAAC,EAAE,MAAM,CAAC;IACd,UAAU,CAAC,EAAE,MAAM,GAAG,IAAI,CAAC;IAC3B,cAAc,CAAC,EAAE,MAAM,CAAC;IACxB,OAAO,CAAC,EAAE,CAAC,GAAG,EAAE,MAAM,KAAK,OAAO,CAAC,IAAI,CAAC,CAAC;CAC1C;AAED,MAAM,WAAW,aAAa;IAC5B,IAAI,EAAE,MAAM,CAAC;IACb,IAAI,EAAE,MAAM,CAAC;IACb,QAAQ,EAAE,eAAe,CAAC;IAC1B,IAAI,EAAE,MAAM,OAAO,CAAC,IAAI,CAAC,CAAC;CAC3B;AA+DD,eAAO,MAAM,YAAY,GAAU,UAAS,aAAkB,KAAG,OAAO,CAAC,aAAa,CA4jBrF,CAAC;AAEF,YAAY,EAAE,OAAO,EAAE,MAAM,cAAc,CAAC;AAC5C,YAAY,EAAE,eAAe,EAAE,MAAM,uBAAuB,CAAC;AAC7D,mBAAmB,YAAY,CAAC;AAChC,OAAO,EAAE,YAAY,EAAE,YAAY,EAAE,qBAAqB,EAAE,MAAM,gBAAgB,CAAC;AACnF,OAAO,EAAE,cAAc,EAAE,aAAa,EAAE,iBAAiB,EAAE,MAAM,eAAe,CAAC;AACjF,OAAO,EAAE,YAAY,EAAE,MAAM,cAAc,CAAC;AAC5C,OAAO,EACL,oBAAoB,EACpB,iBAAiB,EACjB,sBAAsB,EACtB,WAAW,GACZ,MAAM,aAAa,CAAC;AACrB,YAAY,EAAE,WAAW,EAAE,eAAe,EAAE,eAAe,EAAE,MAAM,aAAa,CAAC"}
1
+ {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAkDA,OAAO,EAAE,eAAe,EAAE,MAAM,uBAAuB,CAAC;AAkBxD,MAAM,WAAW,aAAa;IAC5B,IAAI,CAAC,EAAE,MAAM,CAAC;IACd,IAAI,CAAC,EAAE,MAAM,CAAC;IACd,UAAU,CAAC,EAAE,MAAM,GAAG,IAAI,CAAC;IAC3B,cAAc,CAAC,EAAE,MAAM,CAAC;IACxB;;;;;OAKG;IACH,OAAO,CAAC,EAAE,CAAC,GAAG,EAAE,MAAM,KAAK,OAAO,CAAC,IAAI,CAAC,CAAC;CAC1C;AAED,MAAM,WAAW,aAAa;IAC5B,IAAI,EAAE,MAAM,CAAC;IACb,IAAI,EAAE,MAAM,CAAC;IACb,QAAQ,EAAE,eAAe,CAAC;IAC1B,IAAI,EAAE,MAAM,OAAO,CAAC,IAAI,CAAC,CAAC;CAC3B;AA+DD,eAAO,MAAM,YAAY,GAAU,UAAS,aAAkB,KAAG,OAAO,CAAC,aAAa,CAisBrF,CAAC;AAEF,YAAY,EAAE,OAAO,EAAE,MAAM,cAAc,CAAC;AAC5C,YAAY,EAAE,eAAe,EAAE,MAAM,uBAAuB,CAAC;AAC7D,mBAAmB,YAAY,CAAC;AAChC,OAAO,EAAE,YAAY,EAAE,YAAY,EAAE,qBAAqB,EAAE,MAAM,gBAAgB,CAAC;AACnF,OAAO,EAAE,cAAc,EAAE,aAAa,EAAE,iBAAiB,EAAE,MAAM,eAAe,CAAC;AACjF,OAAO,EAAE,YAAY,EAAE,MAAM,cAAc,CAAC;AAC5C,OAAO,EACL,oBAAoB,EACpB,iBAAiB,EACjB,sBAAsB,EACtB,WAAW,GACZ,MAAM,aAAa,CAAC;AACrB,YAAY,EAAE,WAAW,EAAE,eAAe,EAAE,eAAe,EAAE,MAAM,aAAa,CAAC"}