@relauts/spotcheck-service 1.0.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 (124) hide show
  1. package/LICENSE +661 -0
  2. package/NOTICE +19 -0
  3. package/README.md +169 -0
  4. package/dist/api/auth.d.ts +11 -0
  5. package/dist/api/auth.js +32 -0
  6. package/dist/api/auth.js.map +1 -0
  7. package/dist/api/history.d.ts +46 -0
  8. package/dist/api/history.js +172 -0
  9. package/dist/api/history.js.map +1 -0
  10. package/dist/api/saved-run.d.ts +35 -0
  11. package/dist/api/saved-run.js +234 -0
  12. package/dist/api/saved-run.js.map +1 -0
  13. package/dist/api/saved.d.ts +33 -0
  14. package/dist/api/saved.js +209 -0
  15. package/dist/api/saved.js.map +1 -0
  16. package/dist/api/server.d.ts +23 -0
  17. package/dist/api/server.js +852 -0
  18. package/dist/api/server.js.map +1 -0
  19. package/dist/computer-use/actions.d.ts +14 -0
  20. package/dist/computer-use/actions.js +212 -0
  21. package/dist/computer-use/actions.js.map +1 -0
  22. package/dist/computer-use/args.d.ts +11 -0
  23. package/dist/computer-use/args.js +74 -0
  24. package/dist/computer-use/args.js.map +1 -0
  25. package/dist/computer-use/cli.d.ts +1 -0
  26. package/dist/computer-use/cli.js +8 -0
  27. package/dist/computer-use/cli.js.map +1 -0
  28. package/dist/computer-use/client.d.ts +3 -0
  29. package/dist/computer-use/client.js +68 -0
  30. package/dist/computer-use/client.js.map +1 -0
  31. package/dist/computer-use/coords.d.ts +5 -0
  32. package/dist/computer-use/coords.js +21 -0
  33. package/dist/computer-use/coords.js.map +1 -0
  34. package/dist/computer-use/history.d.ts +11 -0
  35. package/dist/computer-use/history.js +59 -0
  36. package/dist/computer-use/history.js.map +1 -0
  37. package/dist/computer-use/index.d.ts +17 -0
  38. package/dist/computer-use/index.js +75 -0
  39. package/dist/computer-use/index.js.map +1 -0
  40. package/dist/computer-use/keys.d.ts +3 -0
  41. package/dist/computer-use/keys.js +50 -0
  42. package/dist/computer-use/keys.js.map +1 -0
  43. package/dist/computer-use/loop.d.ts +22 -0
  44. package/dist/computer-use/loop.js +90 -0
  45. package/dist/computer-use/loop.js.map +1 -0
  46. package/dist/computer-use/safety.d.ts +15 -0
  47. package/dist/computer-use/safety.js +45 -0
  48. package/dist/computer-use/safety.js.map +1 -0
  49. package/dist/computer-use/screenshot.d.ts +5 -0
  50. package/dist/computer-use/screenshot.js +16 -0
  51. package/dist/computer-use/screenshot.js.map +1 -0
  52. package/dist/computer-use/system-prompt.d.ts +11 -0
  53. package/dist/computer-use/system-prompt.js +41 -0
  54. package/dist/computer-use/system-prompt.js.map +1 -0
  55. package/dist/computer-use/types.d.ts +83 -0
  56. package/dist/computer-use/types.js +31 -0
  57. package/dist/computer-use/types.js.map +1 -0
  58. package/dist/playwright/actions.d.ts +81 -0
  59. package/dist/playwright/actions.js +170 -0
  60. package/dist/playwright/actions.js.map +1 -0
  61. package/dist/playwright/chromium.d.ts +10 -0
  62. package/dist/playwright/chromium.js +27 -0
  63. package/dist/playwright/chromium.js.map +1 -0
  64. package/dist/playwright/index.d.ts +2 -0
  65. package/dist/playwright/index.js +64 -0
  66. package/dist/playwright/index.js.map +1 -0
  67. package/dist/playwright/processed.d.ts +11 -0
  68. package/dist/playwright/processed.js +183 -0
  69. package/dist/playwright/processed.js.map +1 -0
  70. package/dist/playwright/session.d.ts +28 -0
  71. package/dist/playwright/session.js +165 -0
  72. package/dist/playwright/session.js.map +1 -0
  73. package/dist/shared/config.d.ts +38 -0
  74. package/dist/shared/config.js +227 -0
  75. package/dist/shared/config.js.map +1 -0
  76. package/dist/shared/cost.d.ts +15 -0
  77. package/dist/shared/cost.js +40 -0
  78. package/dist/shared/cost.js.map +1 -0
  79. package/dist/shared/logger.d.ts +4 -0
  80. package/dist/shared/logger.js +10 -0
  81. package/dist/shared/logger.js.map +1 -0
  82. package/dist/shared/main-module.d.ts +1 -0
  83. package/dist/shared/main-module.js +19 -0
  84. package/dist/shared/main-module.js.map +1 -0
  85. package/dist/shared/models.d.ts +12 -0
  86. package/dist/shared/models.js +40 -0
  87. package/dist/shared/models.js.map +1 -0
  88. package/dist/shared/telemetry.d.ts +9 -0
  89. package/dist/shared/telemetry.js +43 -0
  90. package/dist/shared/telemetry.js.map +1 -0
  91. package/files/model.json +26 -0
  92. package/files/system_prompt.txt +15 -0
  93. package/openapi.yaml +901 -0
  94. package/package.json +60 -0
  95. package/relauts-spotcheck-service-config.example.json +19 -0
  96. package/src/api/auth.ts +40 -0
  97. package/src/api/history.ts +251 -0
  98. package/src/api/saved-run.ts +346 -0
  99. package/src/api/saved.ts +275 -0
  100. package/src/api/server.ts +1198 -0
  101. package/src/computer-use/actions.ts +273 -0
  102. package/src/computer-use/args.ts +97 -0
  103. package/src/computer-use/cli.ts +8 -0
  104. package/src/computer-use/client.ts +81 -0
  105. package/src/computer-use/coords.ts +26 -0
  106. package/src/computer-use/history.ts +80 -0
  107. package/src/computer-use/index.ts +121 -0
  108. package/src/computer-use/keys.ts +54 -0
  109. package/src/computer-use/loop.ts +140 -0
  110. package/src/computer-use/safety.ts +59 -0
  111. package/src/computer-use/screenshot.ts +20 -0
  112. package/src/computer-use/system-prompt.ts +65 -0
  113. package/src/computer-use/types.ts +126 -0
  114. package/src/playwright/actions.ts +332 -0
  115. package/src/playwright/chromium.ts +30 -0
  116. package/src/playwright/index.ts +77 -0
  117. package/src/playwright/processed.ts +253 -0
  118. package/src/playwright/session.ts +220 -0
  119. package/src/shared/config.ts +320 -0
  120. package/src/shared/cost.ts +58 -0
  121. package/src/shared/logger.ts +9 -0
  122. package/src/shared/main-module.ts +20 -0
  123. package/src/shared/models.ts +62 -0
  124. package/src/shared/telemetry.ts +63 -0
@@ -0,0 +1,165 @@
1
+ import { logger } from "../shared/logger.js";
2
+ import { closeBrowser, launchLightChromium } from "./chromium.js";
3
+ import { PROCESSED_DIR, createProcessedScreenshotSaver } from "./processed.js";
4
+ export const BROWSER_SESSION_RESET_MESSAGE = "Browser session was reset. Started a new browser.";
5
+ export class BrowserClosedError extends Error {
6
+ constructor(message = "Browser is closed") {
7
+ super(message);
8
+ this.name = "BrowserClosedError";
9
+ }
10
+ }
11
+ export function createBrowserSession(deps = {}) {
12
+ const launch = deps.launch ?? launchLightChromium;
13
+ let browser;
14
+ let page;
15
+ let saveScreenshot;
16
+ let everOpened = false;
17
+ let needsResetNotice = false;
18
+ let queue = Promise.resolve();
19
+ function enqueue(fn) {
20
+ const run = queue.then(fn, fn);
21
+ queue = run.then(() => undefined, () => undefined);
22
+ return run;
23
+ }
24
+ function isLive() {
25
+ try {
26
+ return Boolean(browser?.isConnected() && page && !page.isClosed());
27
+ }
28
+ catch {
29
+ return false;
30
+ }
31
+ }
32
+ function attachDisconnectHandler(current) {
33
+ current.on("disconnected", () => {
34
+ if (browser !== current) {
35
+ return;
36
+ }
37
+ browser = undefined;
38
+ page = undefined;
39
+ saveScreenshot = undefined;
40
+ needsResetNotice = true;
41
+ logger.info("Chromium disconnected");
42
+ });
43
+ }
44
+ async function drop() {
45
+ const current = browser;
46
+ browser = undefined;
47
+ page = undefined;
48
+ saveScreenshot = undefined;
49
+ await closeBrowser(current);
50
+ }
51
+ function currentStatus() {
52
+ if (!isLive() || !page) {
53
+ return { open: false, url: "" };
54
+ }
55
+ try {
56
+ return { open: true, url: page.url() };
57
+ }
58
+ catch {
59
+ return { open: false, url: "" };
60
+ }
61
+ }
62
+ function requirePage() {
63
+ if (!isLive() || !page) {
64
+ throw new BrowserClosedError();
65
+ }
66
+ return page;
67
+ }
68
+ async function capture(actionName, current) {
69
+ const saver = saveScreenshot ?? createProcessedScreenshotSaver(current, deps.screenshotDir ?? PROCESSED_DIR);
70
+ await saver(actionName);
71
+ }
72
+ async function goBackLocked() {
73
+ const current = requirePage();
74
+ logger.info("Browser chrome: back");
75
+ await current.goBack();
76
+ await capture("back", current);
77
+ return currentStatus();
78
+ }
79
+ async function goForwardLocked() {
80
+ const current = requirePage();
81
+ logger.info("Browser chrome: forward");
82
+ await current.goForward();
83
+ await capture("forward", current);
84
+ return currentStatus();
85
+ }
86
+ async function reloadLocked() {
87
+ const current = requirePage();
88
+ logger.info("Browser chrome: reload");
89
+ await current.reload();
90
+ await capture("reload", current);
91
+ return currentStatus();
92
+ }
93
+ async function ensurePageLocked(config) {
94
+ if (isLive() && page) {
95
+ logger.info("Reusing open Chromium page");
96
+ return { page, sessionReset: false };
97
+ }
98
+ const sessionReset = needsResetNotice || everOpened;
99
+ if (browser || page) {
100
+ logger.info("Chromium session was lost; launching a new browser");
101
+ }
102
+ await drop();
103
+ logger.info(`Launching Chromium for computer-use (headless=${config.headless}, viewport=${config.viewportWidth}x${config.viewportHeight})`);
104
+ const launched = await launch(config);
105
+ attachDisconnectHandler(launched);
106
+ browser = launched;
107
+ const nextPage = await launched.newPage({
108
+ viewport: {
109
+ width: config.viewportWidth,
110
+ height: config.viewportHeight,
111
+ },
112
+ });
113
+ nextPage.setDefaultNavigationTimeout(config.navigationTimeoutMs);
114
+ try {
115
+ logger.info(`Navigating to ${config.targetUrl}`);
116
+ await nextPage.goto(config.targetUrl, {
117
+ waitUntil: "domcontentloaded",
118
+ timeout: config.navigationTimeoutMs,
119
+ });
120
+ }
121
+ catch (error) {
122
+ await drop();
123
+ throw error;
124
+ }
125
+ page = nextPage;
126
+ saveScreenshot = createProcessedScreenshotSaver(nextPage, deps.screenshotDir ?? PROCESSED_DIR);
127
+ everOpened = true;
128
+ needsResetNotice = false;
129
+ return { page, sessionReset };
130
+ }
131
+ async function closeLocked() {
132
+ if (everOpened) {
133
+ needsResetNotice = true;
134
+ }
135
+ if (!browser && !page) {
136
+ return;
137
+ }
138
+ logger.info("Closing Chromium session");
139
+ await drop();
140
+ }
141
+ return {
142
+ isOpen() {
143
+ return isLive();
144
+ },
145
+ getStatus() {
146
+ return currentStatus();
147
+ },
148
+ ensurePage(config) {
149
+ return enqueue(() => ensurePageLocked(config));
150
+ },
151
+ close() {
152
+ return enqueue(() => closeLocked());
153
+ },
154
+ goBack() {
155
+ return enqueue(() => goBackLocked());
156
+ },
157
+ goForward() {
158
+ return enqueue(() => goForwardLocked());
159
+ },
160
+ reload() {
161
+ return enqueue(() => reloadLocked());
162
+ },
163
+ };
164
+ }
165
+ //# sourceMappingURL=session.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"session.js","sourceRoot":"","sources":["../../src/playwright/session.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,38 @@
1
+ export declare const DEFAULT_GEMINI_MODEL = "gemini-3.6-flash";
2
+ export declare const DEFAULT_AGENT_MAX_TURNS = 15;
3
+ export declare const DEFAULT_SERVICE_PORT = 18732;
4
+ export declare const DEFAULT_MAX_SAVED_RUNS = 2;
5
+ export declare const GEMINI_THINKING_LEVELS: readonly ["minimal", "low", "medium", "high"];
6
+ export type GeminiThinkingLevel = (typeof GEMINI_THINKING_LEVELS)[number];
7
+ export declare const DEFAULT_GEMINI_THINKING_LEVEL: GeminiThinkingLevel;
8
+ export declare const CONFIG_FILE_NAME = "relauts-spotcheck-service-config.json";
9
+ export declare const GEMINI_SAFETY_POLICIES: readonly ["financial_transactions", "sensitive_data_modification", "communication_tool", "account_creation", "data_modification", "user_consent_management", "legal_terms_and_agreements"];
10
+ export type GeminiSafetyPolicy = (typeof GEMINI_SAFETY_POLICIES)[number];
11
+ export interface AppConfig {
12
+ readonly targetUrl: string;
13
+ readonly navigationTimeoutMs: number;
14
+ readonly headless: boolean;
15
+ readonly chromiumSandbox: boolean;
16
+ readonly webPort: number;
17
+ readonly viewportWidth: number;
18
+ readonly viewportHeight: number;
19
+ readonly geminiApiKey: string | undefined;
20
+ readonly geminiModel: string;
21
+ readonly geminiThinkingLevel: GeminiThinkingLevel;
22
+ readonly geminiSeed: number | undefined;
23
+ readonly agentMaxTurns: number;
24
+ readonly geminiDisabledSafetyPolicies: readonly GeminiSafetyPolicy[];
25
+ readonly apiToken: string | undefined;
26
+ readonly corsOrigins: readonly string[];
27
+ readonly savedDir: string;
28
+ readonly processedDir: string;
29
+ readonly historyDir: string;
30
+ readonly maxSavedRuns: number;
31
+ readonly installationId: string | undefined;
32
+ readonly telemetryUrl: string | undefined;
33
+ }
34
+ export declare function resolveConfigFilePath(): string;
35
+ export declare function readConfigFile(filePath: string): Record<string, unknown>;
36
+ export declare function loadConfig(source?: Record<string, unknown>): AppConfig;
37
+ export declare function requireGeminiApiKey(config: AppConfig): string;
38
+ export declare function requireApiToken(config: AppConfig): string;
@@ -0,0 +1,227 @@
1
+ import fs from "node:fs";
2
+ import path from "node:path";
3
+ import { fileURLToPath } from "node:url";
4
+ export const DEFAULT_GEMINI_MODEL = "gemini-3.6-flash";
5
+ export const DEFAULT_AGENT_MAX_TURNS = 15;
6
+ export const DEFAULT_SERVICE_PORT = 18732;
7
+ export const DEFAULT_MAX_SAVED_RUNS = 2;
8
+ export const GEMINI_THINKING_LEVELS = ["minimal", "low", "medium", "high"];
9
+ export const DEFAULT_GEMINI_THINKING_LEVEL = "minimal";
10
+ export const CONFIG_FILE_NAME = "relauts-spotcheck-service-config.json";
11
+ export const GEMINI_SAFETY_POLICIES = [
12
+ "financial_transactions",
13
+ "sensitive_data_modification",
14
+ "communication_tool",
15
+ "account_creation",
16
+ "data_modification",
17
+ "user_consent_management",
18
+ "legal_terms_and_agreements",
19
+ ];
20
+ function parseBoolean(value, fallback) {
21
+ if (value === undefined) {
22
+ return fallback;
23
+ }
24
+ if (typeof value === "boolean") {
25
+ return value;
26
+ }
27
+ if (typeof value === "string") {
28
+ const normalized = value.trim().toLowerCase();
29
+ if (normalized === "true" || normalized === "1") {
30
+ return true;
31
+ }
32
+ if (normalized === "false" || normalized === "0") {
33
+ return false;
34
+ }
35
+ }
36
+ throw new Error(`Invalid boolean value: "${String(value)}"`);
37
+ }
38
+ function parsePositiveInt(value, fallback) {
39
+ if (value === undefined) {
40
+ return fallback;
41
+ }
42
+ const parsed = typeof value === "number" ? value : Number(value);
43
+ if (!Number.isInteger(parsed) || parsed <= 0) {
44
+ throw new Error(`Invalid positive integer: "${String(value)}"`);
45
+ }
46
+ return parsed;
47
+ }
48
+ function parseHttpUrl(value) {
49
+ const raw = typeof value === "string" ? value : "https://example.com";
50
+ return parseRequiredHttpUrl(raw);
51
+ }
52
+ function parseRequiredHttpUrl(raw) {
53
+ const url = new URL(raw);
54
+ if (url.protocol !== "http:" && url.protocol !== "https:") {
55
+ throw new Error(`URL must use http or https: "${raw}"`);
56
+ }
57
+ return url.toString();
58
+ }
59
+ function parseOptionalHttpUrl(value) {
60
+ if (value === undefined || value === null) {
61
+ return undefined;
62
+ }
63
+ if (typeof value !== "string") {
64
+ throw new Error(`URL must use http or https: "${String(value)}"`);
65
+ }
66
+ const trimmed = value.trim();
67
+ if (!trimmed) {
68
+ return undefined;
69
+ }
70
+ return parseRequiredHttpUrl(trimmed);
71
+ }
72
+ function parseOptionalString(value) {
73
+ if (typeof value !== "string") {
74
+ return undefined;
75
+ }
76
+ const trimmed = value.trim();
77
+ return trimmed ? trimmed : undefined;
78
+ }
79
+ function parseOptionalSeed(value) {
80
+ if (value === undefined || value === null) {
81
+ return undefined;
82
+ }
83
+ if (typeof value === "string" && !value.trim()) {
84
+ return undefined;
85
+ }
86
+ const parsed = typeof value === "number" ? value : Number(value);
87
+ if (!Number.isInteger(parsed)) {
88
+ throw new Error(`Invalid seed: "${String(value)}"`);
89
+ }
90
+ return parsed;
91
+ }
92
+ function parseThinkingLevel(value, fallback) {
93
+ if (value === undefined) {
94
+ return fallback;
95
+ }
96
+ const normalized = String(value).trim().toLowerCase();
97
+ if (GEMINI_THINKING_LEVELS.includes(normalized)) {
98
+ return normalized;
99
+ }
100
+ throw new Error(`Invalid thinking level: "${String(value)}". Use ${GEMINI_THINKING_LEVELS.join(", ")}`);
101
+ }
102
+ /**
103
+ * Runs target QA environments, so every predefined safety policy is disabled by
104
+ * default and Gemini stops gating actions such as checkout clicks. Omit the
105
+ * field to keep that default, set it to "none" to keep all policies active, or
106
+ * pass a list to disable only those. Gemini may still return require_confirmation
107
+ * regardless, so callers must keep handling safety decisions.
108
+ */
109
+ function parseSafetyPolicies(value) {
110
+ if (value === undefined || value === null) {
111
+ return GEMINI_SAFETY_POLICIES;
112
+ }
113
+ if (Array.isArray(value)) {
114
+ if (value.length === 0) {
115
+ return GEMINI_SAFETY_POLICIES;
116
+ }
117
+ return value.map((entry) => parseSafetyPolicy(String(entry)));
118
+ }
119
+ if (typeof value !== "string") {
120
+ throw new Error(`Invalid safety policies. Use ${GEMINI_SAFETY_POLICIES.join(", ")}, or none`);
121
+ }
122
+ const trimmed = value.trim();
123
+ if (!trimmed) {
124
+ return GEMINI_SAFETY_POLICIES;
125
+ }
126
+ if (trimmed.toLowerCase() === "none") {
127
+ return [];
128
+ }
129
+ return trimmed.split(",").map((entry) => parseSafetyPolicy(entry));
130
+ }
131
+ function parseSafetyPolicy(entry) {
132
+ const normalized = entry.trim().toLowerCase();
133
+ if (!GEMINI_SAFETY_POLICIES.includes(normalized)) {
134
+ throw new Error(`Invalid safety policy: "${entry.trim()}". Use ${GEMINI_SAFETY_POLICIES.join(", ")}, or none`);
135
+ }
136
+ return normalized;
137
+ }
138
+ function parseCorsOrigins(value) {
139
+ if (value === undefined || value === null) {
140
+ return [];
141
+ }
142
+ const entries = Array.isArray(value)
143
+ ? value.map((entry) => String(entry))
144
+ : typeof value === "string"
145
+ ? value.split(",")
146
+ : null;
147
+ if (!entries) {
148
+ throw new Error(`Invalid CORS origins: "${String(value)}"`);
149
+ }
150
+ return entries.map((entry) => entry.trim()).filter((entry) => entry.length > 0);
151
+ }
152
+ function parseDirPath(value, fallbackRelative) {
153
+ const raw = typeof value === "string" && value.trim() ? value.trim() : fallbackRelative;
154
+ return path.resolve(process.cwd(), raw);
155
+ }
156
+ function pick(source, camel, envKey) {
157
+ if (Object.prototype.hasOwnProperty.call(source, camel)) {
158
+ return source[camel];
159
+ }
160
+ return source[envKey];
161
+ }
162
+ function resolveRepoRoot() {
163
+ return path.resolve(path.dirname(fileURLToPath(import.meta.url)), "../..");
164
+ }
165
+ export function resolveConfigFilePath() {
166
+ const fromCwd = path.resolve(process.cwd(), CONFIG_FILE_NAME);
167
+ if (fs.existsSync(fromCwd)) {
168
+ return fromCwd;
169
+ }
170
+ return path.resolve(resolveRepoRoot(), "..", CONFIG_FILE_NAME);
171
+ }
172
+ export function readConfigFile(filePath) {
173
+ if (!fs.existsSync(filePath)) {
174
+ throw new Error(`Config file not found: ${filePath}`);
175
+ }
176
+ let parsed;
177
+ try {
178
+ parsed = JSON.parse(fs.readFileSync(filePath, "utf8"));
179
+ }
180
+ catch (error) {
181
+ const message = error instanceof Error ? error.message : String(error);
182
+ throw new Error(`Invalid config JSON (${filePath}): ${message}`);
183
+ }
184
+ if (parsed === null || typeof parsed !== "object" || Array.isArray(parsed)) {
185
+ throw new Error(`Config file must be a JSON object: ${filePath}`);
186
+ }
187
+ return parsed;
188
+ }
189
+ export function loadConfig(source) {
190
+ const raw = source ?? readConfigFile(resolveConfigFilePath());
191
+ return {
192
+ targetUrl: parseHttpUrl(pick(raw, "targetUrl", "TARGET_URL")),
193
+ navigationTimeoutMs: parsePositiveInt(pick(raw, "navigationTimeoutMs", "NAVIGATION_TIMEOUT_MS"), 30_000),
194
+ headless: parseBoolean(pick(raw, "headless", "HEADLESS"), true),
195
+ chromiumSandbox: parseBoolean(pick(raw, "chromiumSandbox", "CHROMIUM_SANDBOX"), true),
196
+ webPort: parsePositiveInt(pick(raw, "port", "PORT"), DEFAULT_SERVICE_PORT),
197
+ viewportWidth: parsePositiveInt(pick(raw, "viewportWidth", "VIEWPORT_WIDTH"), 1024),
198
+ viewportHeight: parsePositiveInt(pick(raw, "viewportHeight", "VIEWPORT_HEIGHT"), 768),
199
+ geminiApiKey: parseOptionalString(pick(raw, "geminiApiKey", "GEMINI_API_KEY")),
200
+ geminiModel: parseOptionalString(pick(raw, "geminiModel", "GEMINI_MODEL")) ?? DEFAULT_GEMINI_MODEL,
201
+ geminiThinkingLevel: parseThinkingLevel(pick(raw, "geminiThinkingLevel", "GEMINI_THINKING_LEVEL"), DEFAULT_GEMINI_THINKING_LEVEL),
202
+ geminiSeed: parseOptionalSeed(pick(raw, "seed", "SEED")),
203
+ agentMaxTurns: parsePositiveInt(pick(raw, "agentMaxTurns", "AGENT_MAX_TURNS"), DEFAULT_AGENT_MAX_TURNS),
204
+ geminiDisabledSafetyPolicies: parseSafetyPolicies(pick(raw, "geminiDisabledSafetyPolicies", "GEMINI_DISABLED_SAFETY_POLICIES")),
205
+ apiToken: parseOptionalString(pick(raw, "apiToken", "API_TOKEN")),
206
+ corsOrigins: parseCorsOrigins(pick(raw, "corsOrigins", "CORS_ORIGINS")),
207
+ savedDir: parseDirPath(pick(raw, "savedDir", "SAVED_DIR"), "saved"),
208
+ processedDir: parseDirPath(pick(raw, "processedDir", "PROCESSED_DIR"), "processed"),
209
+ historyDir: parseDirPath(pick(raw, "historyDir", "HISTORY_DIR"), "history"),
210
+ maxSavedRuns: parsePositiveInt(pick(raw, "maxSavedRuns", "MAX_SAVED_RUNS"), DEFAULT_MAX_SAVED_RUNS),
211
+ installationId: parseOptionalString(pick(raw, "installationId", "INSTALLATION_ID")),
212
+ telemetryUrl: parseOptionalHttpUrl(pick(raw, "telemetryUrl", "TELEMETRY_URL")),
213
+ };
214
+ }
215
+ export function requireGeminiApiKey(config) {
216
+ if (!config.geminiApiKey) {
217
+ throw new Error("GEMINI_API_KEY is required");
218
+ }
219
+ return config.geminiApiKey;
220
+ }
221
+ export function requireApiToken(config) {
222
+ if (!config.apiToken) {
223
+ throw new Error("API_TOKEN is required");
224
+ }
225
+ return config.apiToken;
226
+ }
227
+ //# sourceMappingURL=config.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"config.js","sourceRoot":"","sources":["../../src/shared/config.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,15 @@
1
+ export interface TokenUsage {
2
+ readonly inputTokens: number;
3
+ readonly outputTokens: number;
4
+ readonly thoughtTokens: number;
5
+ readonly cachedTokens: number;
6
+ }
7
+ export declare const EMPTY_USAGE: TokenUsage;
8
+ export interface ModelPrices {
9
+ readonly input_price_per_million: number;
10
+ readonly output_price_per_million: number;
11
+ readonly cache_price_per_million: number;
12
+ }
13
+ export declare function parseUsage(value: unknown): TokenUsage;
14
+ export declare function addUsage(left: TokenUsage, right: TokenUsage): TokenUsage;
15
+ export declare function computeCostUsd(usage: TokenUsage, prices: ModelPrices): number;
@@ -0,0 +1,40 @@
1
+ export const EMPTY_USAGE = {
2
+ inputTokens: 0,
3
+ outputTokens: 0,
4
+ thoughtTokens: 0,
5
+ cachedTokens: 0,
6
+ };
7
+ function toCount(value) {
8
+ return typeof value === "number" && Number.isFinite(value) && value > 0 ? Math.floor(value) : 0;
9
+ }
10
+ export function parseUsage(value) {
11
+ if (typeof value !== "object" || value === null || Array.isArray(value)) {
12
+ return EMPTY_USAGE;
13
+ }
14
+ const raw = value;
15
+ return {
16
+ inputTokens: toCount(raw.total_input_tokens),
17
+ outputTokens: toCount(raw.total_output_tokens),
18
+ thoughtTokens: toCount(raw.total_thought_tokens),
19
+ cachedTokens: toCount(raw.total_cached_tokens),
20
+ };
21
+ }
22
+ export function addUsage(left, right) {
23
+ return {
24
+ inputTokens: left.inputTokens + right.inputTokens,
25
+ outputTokens: left.outputTokens + right.outputTokens,
26
+ thoughtTokens: left.thoughtTokens + right.thoughtTokens,
27
+ cachedTokens: left.cachedTokens + right.cachedTokens,
28
+ };
29
+ }
30
+ export function computeCostUsd(usage, prices) {
31
+ const cached = Math.min(usage.cachedTokens, usage.inputTokens);
32
+ const input = usage.inputTokens - cached;
33
+ const output = usage.outputTokens + usage.thoughtTokens;
34
+ const cost = (input * prices.input_price_per_million +
35
+ cached * prices.cache_price_per_million +
36
+ output * prices.output_price_per_million) /
37
+ 1_000_000;
38
+ return Number(cost.toFixed(6));
39
+ }
40
+ //# sourceMappingURL=cost.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"cost.js","sourceRoot":"","sources":["../../src/shared/cost.ts"],"names":[],"mappings":"AAOA,MAAM,CAAC,MAAM,WAAW,GAAe;IACrC,WAAW,EAAE,CAAC;IACd,YAAY,EAAE,CAAC;IACf,aAAa,EAAE,CAAC;IAChB,YAAY,EAAE,CAAC;CAChB,CAAC;AAQF,SAAS,OAAO,CAAC,KAAc;IAC7B,OAAO,OAAO,KAAK,KAAK,QAAQ,IAAI,MAAM,CAAC,QAAQ,CAAC,KAAK,CAAC,IAAI,KAAK,GAAG,CAAC,CAAC,CAAC,CAAC,IAAI,CAAC,KAAK,CAAC,KAAK,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC;AAClG,CAAC;AAED,MAAM,UAAU,UAAU,CAAC,KAAc;IACvC,IAAI,OAAO,KAAK,KAAK,QAAQ,IAAI,KAAK,KAAK,IAAI,IAAI,KAAK,CAAC,OAAO,CAAC,KAAK,CAAC,EAAE,CAAC;QACxE,OAAO,WAAW,CAAC;IACrB,CAAC;IAED,MAAM,GAAG,GAAG,KAAgC,CAAC;IAC7C,OAAO;QACL,WAAW,EAAE,OAAO,CAAC,GAAG,CAAC,kBAAkB,CAAC;QAC5C,YAAY,EAAE,OAAO,CAAC,GAAG,CAAC,mBAAmB,CAAC;QAC9C,aAAa,EAAE,OAAO,CAAC,GAAG,CAAC,oBAAoB,CAAC;QAChD,YAAY,EAAE,OAAO,CAAC,GAAG,CAAC,mBAAmB,CAAC;KAC/C,CAAC;AACJ,CAAC;AAED,MAAM,UAAU,QAAQ,CAAC,IAAgB,EAAE,KAAiB;IAC1D,OAAO;QACL,WAAW,EAAE,IAAI,CAAC,WAAW,GAAG,KAAK,CAAC,WAAW;QACjD,YAAY,EAAE,IAAI,CAAC,YAAY,GAAG,KAAK,CAAC,YAAY;QACpD,aAAa,EAAE,IAAI,CAAC,aAAa,GAAG,KAAK,CAAC,aAAa;QACvD,YAAY,EAAE,IAAI,CAAC,YAAY,GAAG,KAAK,CAAC,YAAY;KACrD,CAAC;AACJ,CAAC;AAED,MAAM,UAAU,cAAc,CAAC,KAAiB,EAAE,MAAmB;IACnE,MAAM,MAAM,GAAG,IAAI,CAAC,GAAG,CAAC,KAAK,CAAC,YAAY,EAAE,KAAK,CAAC,WAAW,CAAC,CAAC;IAC/D,MAAM,KAAK,GAAG,KAAK,CAAC,WAAW,GAAG,MAAM,CAAC;IACzC,MAAM,MAAM,GAAG,KAAK,CAAC,YAAY,GAAG,KAAK,CAAC,aAAa,CAAC;IACxD,MAAM,IAAI,GACR,CAAC,KAAK,GAAG,MAAM,CAAC,uBAAuB;QACrC,MAAM,GAAG,MAAM,CAAC,uBAAuB;QACvC,MAAM,GAAG,MAAM,CAAC,wBAAwB,CAAC;QAC3C,SAAS,CAAC;IACZ,OAAO,MAAM,CAAC,IAAI,CAAC,OAAO,CAAC,CAAC,CAAC,CAAC,CAAC;AACjC,CAAC"}
@@ -0,0 +1,4 @@
1
+ export declare const logger: {
2
+ info(message: string): void;
3
+ error(message: string, error?: unknown): void;
4
+ };
@@ -0,0 +1,10 @@
1
+ export const logger = {
2
+ info(message) {
3
+ console.log(`[${new Date().toISOString()}] INFO ${message}`);
4
+ },
5
+ error(message, error) {
6
+ const detail = error instanceof Error ? error.stack ?? error.message : String(error ?? "");
7
+ console.error(`[${new Date().toISOString()}] ERROR ${message}${detail ? `\n${detail}` : ""}`);
8
+ },
9
+ };
10
+ //# sourceMappingURL=logger.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"logger.js","sourceRoot":"","sources":["../../src/shared/logger.ts"],"names":[],"mappings":"AAAA,MAAM,CAAC,MAAM,MAAM,GAAG;IACpB,IAAI,CAAC,OAAe;QAClB,OAAO,CAAC,GAAG,CAAC,IAAI,IAAI,IAAI,EAAE,CAAC,WAAW,EAAE,WAAW,OAAO,EAAE,CAAC,CAAC;IAChE,CAAC;IACD,KAAK,CAAC,OAAe,EAAE,KAAe;QACpC,MAAM,MAAM,GAAG,KAAK,YAAY,KAAK,CAAC,CAAC,CAAC,KAAK,CAAC,KAAK,IAAI,KAAK,CAAC,OAAO,CAAC,CAAC,CAAC,MAAM,CAAC,KAAK,IAAI,EAAE,CAAC,CAAC;QAC3F,OAAO,CAAC,KAAK,CAAC,IAAI,IAAI,IAAI,EAAE,CAAC,WAAW,EAAE,WAAW,OAAO,GAAG,MAAM,CAAC,CAAC,CAAC,KAAK,MAAM,EAAE,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,CAAC;IAChG,CAAC;CACF,CAAC"}
@@ -0,0 +1 @@
1
+ export declare function isMainModule(moduleUrl: string, entry?: string | undefined): boolean;
@@ -0,0 +1,19 @@
1
+ import fs from "node:fs";
2
+ import path from "node:path";
3
+ import { fileURLToPath } from "node:url";
4
+ function realPath(filePath) {
5
+ const resolved = path.resolve(filePath);
6
+ try {
7
+ return fs.realpathSync.native(resolved);
8
+ }
9
+ catch {
10
+ return resolved;
11
+ }
12
+ }
13
+ export function isMainModule(moduleUrl, entry = process.argv[1]) {
14
+ if (!entry) {
15
+ return false;
16
+ }
17
+ return realPath(fileURLToPath(moduleUrl)) === realPath(entry);
18
+ }
19
+ //# sourceMappingURL=main-module.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"main-module.js","sourceRoot":"","sources":["../../src/shared/main-module.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,MAAM,SAAS,CAAC;AACzB,OAAO,IAAI,MAAM,WAAW,CAAC;AAC7B,OAAO,EAAE,aAAa,EAAE,MAAM,UAAU,CAAC;AAEzC,SAAS,QAAQ,CAAC,QAAgB;IAChC,MAAM,QAAQ,GAAG,IAAI,CAAC,OAAO,CAAC,QAAQ,CAAC,CAAC;IACxC,IAAI,CAAC;QACH,OAAO,EAAE,CAAC,YAAY,CAAC,MAAM,CAAC,QAAQ,CAAC,CAAC;IAC1C,CAAC;IAAC,MAAM,CAAC;QACP,OAAO,QAAQ,CAAC;IAClB,CAAC;AACH,CAAC;AAED,MAAM,UAAU,YAAY,CAAC,SAAiB,EAAE,KAAK,GAAG,OAAO,CAAC,IAAI,CAAC,CAAC,CAAC;IACrE,IAAI,CAAC,KAAK,EAAE,CAAC;QACX,OAAO,KAAK,CAAC;IACf,CAAC;IAED,OAAO,QAAQ,CAAC,aAAa,CAAC,SAAS,CAAC,CAAC,KAAK,QAAQ,CAAC,KAAK,CAAC,CAAC;AAChE,CAAC"}
@@ -0,0 +1,12 @@
1
+ export declare const MODEL_JSON_PATH: string;
2
+ export interface ModelEntry {
3
+ readonly provider: string;
4
+ readonly model: string;
5
+ readonly input_price_per_million: number;
6
+ readonly output_price_per_million: number;
7
+ readonly cache_price_per_million: number;
8
+ readonly description: string;
9
+ }
10
+ export declare function loadModels(filePath?: string): Promise<ModelEntry[]>;
11
+ export declare function getModelEntry(model: string, models: readonly ModelEntry[]): ModelEntry;
12
+ export declare function assertAllowedModel(model: string, models: readonly ModelEntry[]): string;
@@ -0,0 +1,40 @@
1
+ import fs from "node:fs/promises";
2
+ import path from "node:path";
3
+ import { fileURLToPath } from "node:url";
4
+ export const MODEL_JSON_PATH = path.resolve(path.dirname(fileURLToPath(import.meta.url)), "../../files/model.json");
5
+ function isModelEntry(value) {
6
+ if (typeof value !== "object" || value === null || Array.isArray(value)) {
7
+ return false;
8
+ }
9
+ const entry = value;
10
+ return (typeof entry.provider === "string" &&
11
+ typeof entry.model === "string" &&
12
+ typeof entry.input_price_per_million === "number" &&
13
+ typeof entry.output_price_per_million === "number" &&
14
+ typeof entry.cache_price_per_million === "number" &&
15
+ typeof entry.description === "string" &&
16
+ entry.model.trim().length > 0);
17
+ }
18
+ export async function loadModels(filePath = MODEL_JSON_PATH) {
19
+ const raw = await fs.readFile(filePath, "utf8");
20
+ const parsed = JSON.parse(raw);
21
+ if (!Array.isArray(parsed) || parsed.length === 0) {
22
+ throw new Error("model.json must be a non-empty array");
23
+ }
24
+ if (!parsed.every(isModelEntry)) {
25
+ throw new Error("model.json has invalid model entries");
26
+ }
27
+ return parsed;
28
+ }
29
+ export function getModelEntry(model, models) {
30
+ const trimmed = model.trim();
31
+ const match = models.find((entry) => entry.model === trimmed);
32
+ if (!match) {
33
+ throw new Error(`Unknown model: ${trimmed}`);
34
+ }
35
+ return match;
36
+ }
37
+ export function assertAllowedModel(model, models) {
38
+ return getModelEntry(model, models).model;
39
+ }
40
+ //# sourceMappingURL=models.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"models.js","sourceRoot":"","sources":["../../src/shared/models.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,MAAM,kBAAkB,CAAC;AAClC,OAAO,IAAI,MAAM,WAAW,CAAC;AAC7B,OAAO,EAAE,aAAa,EAAE,MAAM,UAAU,CAAC;AAEzC,MAAM,CAAC,MAAM,eAAe,GAAG,IAAI,CAAC,OAAO,CACzC,IAAI,CAAC,OAAO,CAAC,aAAa,CAAC,MAAM,CAAC,IAAI,CAAC,GAAG,CAAC,CAAC,EAC5C,wBAAwB,CACzB,CAAC;AAWF,SAAS,YAAY,CAAC,KAAc;IAClC,IAAI,OAAO,KAAK,KAAK,QAAQ,IAAI,KAAK,KAAK,IAAI,IAAI,KAAK,CAAC,OAAO,CAAC,KAAK,CAAC,EAAE,CAAC;QACxE,OAAO,KAAK,CAAC;IACf,CAAC;IAED,MAAM,KAAK,GAAG,KAAgC,CAAC;IAC/C,OAAO,CACL,OAAO,KAAK,CAAC,QAAQ,KAAK,QAAQ;QAClC,OAAO,KAAK,CAAC,KAAK,KAAK,QAAQ;QAC/B,OAAO,KAAK,CAAC,uBAAuB,KAAK,QAAQ;QACjD,OAAO,KAAK,CAAC,wBAAwB,KAAK,QAAQ;QAClD,OAAO,KAAK,CAAC,uBAAuB,KAAK,QAAQ;QACjD,OAAO,KAAK,CAAC,WAAW,KAAK,QAAQ;QACrC,KAAK,CAAC,KAAK,CAAC,IAAI,EAAE,CAAC,MAAM,GAAG,CAAC,CAC9B,CAAC;AACJ,CAAC;AAED,MAAM,CAAC,KAAK,UAAU,UAAU,CAAC,QAAQ,GAAG,eAAe;IACzD,MAAM,GAAG,GAAG,MAAM,EAAE,CAAC,QAAQ,CAAC,QAAQ,EAAE,MAAM,CAAC,CAAC;IAChD,MAAM,MAAM,GAAY,IAAI,CAAC,KAAK,CAAC,GAAG,CAAC,CAAC;IACxC,IAAI,CAAC,KAAK,CAAC,OAAO,CAAC,MAAM,CAAC,IAAI,MAAM,CAAC,MAAM,KAAK,CAAC,EAAE,CAAC;QAClD,MAAM,IAAI,KAAK,CAAC,sCAAsC,CAAC,CAAC;IAC1D,CAAC;IAED,IAAI,CAAC,MAAM,CAAC,KAAK,CAAC,YAAY,CAAC,EAAE,CAAC;QAChC,MAAM,IAAI,KAAK,CAAC,sCAAsC,CAAC,CAAC;IAC1D,CAAC;IAED,OAAO,MAAM,CAAC;AAChB,CAAC;AAED,MAAM,UAAU,aAAa,CAAC,KAAa,EAAE,MAA6B;IACxE,MAAM,OAAO,GAAG,KAAK,CAAC,IAAI,EAAE,CAAC;IAC7B,MAAM,KAAK,GAAG,MAAM,CAAC,IAAI,CAAC,CAAC,KAAK,EAAE,EAAE,CAAC,KAAK,CAAC,KAAK,KAAK,OAAO,CAAC,CAAC;IAC9D,IAAI,CAAC,KAAK,EAAE,CAAC;QACX,MAAM,IAAI,KAAK,CAAC,kBAAkB,OAAO,EAAE,CAAC,CAAC;IAC/C,CAAC;IAED,OAAO,KAAK,CAAC;AACf,CAAC;AAED,MAAM,UAAU,kBAAkB,CAAC,KAAa,EAAE,MAA6B;IAC7E,OAAO,aAAa,CAAC,KAAK,EAAE,MAAM,CAAC,CAAC,KAAK,CAAC;AAC5C,CAAC"}
@@ -0,0 +1,9 @@
1
+ import type { AppConfig } from "./config.js";
2
+ export declare const MIN_AUTOMATION_DURATION_MS = 1000;
3
+ export type AutomationReporter = (startedAt: Date, endedAt: Date) => void;
4
+ export interface TelemetryPostDeps {
5
+ readonly fetch?: typeof fetch;
6
+ readonly randomUUID?: () => string;
7
+ }
8
+ export declare function createAutomationReporter(config: Pick<AppConfig, "installationId" | "telemetryUrl">, deps?: TelemetryPostDeps): AutomationReporter;
9
+ export declare function postSuccessfulAutomation(config: Pick<AppConfig, "installationId" | "telemetryUrl">, startedAt: Date, endedAt: Date, deps?: TelemetryPostDeps): Promise<void>;