@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.
- package/LICENSE +661 -0
- package/NOTICE +19 -0
- package/README.md +169 -0
- package/dist/api/auth.d.ts +11 -0
- package/dist/api/auth.js +32 -0
- package/dist/api/auth.js.map +1 -0
- package/dist/api/history.d.ts +46 -0
- package/dist/api/history.js +172 -0
- package/dist/api/history.js.map +1 -0
- package/dist/api/saved-run.d.ts +35 -0
- package/dist/api/saved-run.js +234 -0
- package/dist/api/saved-run.js.map +1 -0
- package/dist/api/saved.d.ts +33 -0
- package/dist/api/saved.js +209 -0
- package/dist/api/saved.js.map +1 -0
- package/dist/api/server.d.ts +23 -0
- package/dist/api/server.js +852 -0
- package/dist/api/server.js.map +1 -0
- package/dist/computer-use/actions.d.ts +14 -0
- package/dist/computer-use/actions.js +212 -0
- package/dist/computer-use/actions.js.map +1 -0
- package/dist/computer-use/args.d.ts +11 -0
- package/dist/computer-use/args.js +74 -0
- package/dist/computer-use/args.js.map +1 -0
- package/dist/computer-use/cli.d.ts +1 -0
- package/dist/computer-use/cli.js +8 -0
- package/dist/computer-use/cli.js.map +1 -0
- package/dist/computer-use/client.d.ts +3 -0
- package/dist/computer-use/client.js +68 -0
- package/dist/computer-use/client.js.map +1 -0
- package/dist/computer-use/coords.d.ts +5 -0
- package/dist/computer-use/coords.js +21 -0
- package/dist/computer-use/coords.js.map +1 -0
- package/dist/computer-use/history.d.ts +11 -0
- package/dist/computer-use/history.js +59 -0
- package/dist/computer-use/history.js.map +1 -0
- package/dist/computer-use/index.d.ts +17 -0
- package/dist/computer-use/index.js +75 -0
- package/dist/computer-use/index.js.map +1 -0
- package/dist/computer-use/keys.d.ts +3 -0
- package/dist/computer-use/keys.js +50 -0
- package/dist/computer-use/keys.js.map +1 -0
- package/dist/computer-use/loop.d.ts +22 -0
- package/dist/computer-use/loop.js +90 -0
- package/dist/computer-use/loop.js.map +1 -0
- package/dist/computer-use/safety.d.ts +15 -0
- package/dist/computer-use/safety.js +45 -0
- package/dist/computer-use/safety.js.map +1 -0
- package/dist/computer-use/screenshot.d.ts +5 -0
- package/dist/computer-use/screenshot.js +16 -0
- package/dist/computer-use/screenshot.js.map +1 -0
- package/dist/computer-use/system-prompt.d.ts +11 -0
- package/dist/computer-use/system-prompt.js +41 -0
- package/dist/computer-use/system-prompt.js.map +1 -0
- package/dist/computer-use/types.d.ts +83 -0
- package/dist/computer-use/types.js +31 -0
- package/dist/computer-use/types.js.map +1 -0
- package/dist/playwright/actions.d.ts +81 -0
- package/dist/playwright/actions.js +170 -0
- package/dist/playwright/actions.js.map +1 -0
- package/dist/playwright/chromium.d.ts +10 -0
- package/dist/playwright/chromium.js +27 -0
- package/dist/playwright/chromium.js.map +1 -0
- package/dist/playwright/index.d.ts +2 -0
- package/dist/playwright/index.js +64 -0
- package/dist/playwright/index.js.map +1 -0
- package/dist/playwright/processed.d.ts +11 -0
- package/dist/playwright/processed.js +183 -0
- package/dist/playwright/processed.js.map +1 -0
- package/dist/playwright/session.d.ts +28 -0
- package/dist/playwright/session.js +165 -0
- package/dist/playwright/session.js.map +1 -0
- package/dist/shared/config.d.ts +38 -0
- package/dist/shared/config.js +227 -0
- package/dist/shared/config.js.map +1 -0
- package/dist/shared/cost.d.ts +15 -0
- package/dist/shared/cost.js +40 -0
- package/dist/shared/cost.js.map +1 -0
- package/dist/shared/logger.d.ts +4 -0
- package/dist/shared/logger.js +10 -0
- package/dist/shared/logger.js.map +1 -0
- package/dist/shared/main-module.d.ts +1 -0
- package/dist/shared/main-module.js +19 -0
- package/dist/shared/main-module.js.map +1 -0
- package/dist/shared/models.d.ts +12 -0
- package/dist/shared/models.js +40 -0
- package/dist/shared/models.js.map +1 -0
- package/dist/shared/telemetry.d.ts +9 -0
- package/dist/shared/telemetry.js +43 -0
- package/dist/shared/telemetry.js.map +1 -0
- package/files/model.json +26 -0
- package/files/system_prompt.txt +15 -0
- package/openapi.yaml +901 -0
- package/package.json +60 -0
- package/relauts-spotcheck-service-config.example.json +19 -0
- package/src/api/auth.ts +40 -0
- package/src/api/history.ts +251 -0
- package/src/api/saved-run.ts +346 -0
- package/src/api/saved.ts +275 -0
- package/src/api/server.ts +1198 -0
- package/src/computer-use/actions.ts +273 -0
- package/src/computer-use/args.ts +97 -0
- package/src/computer-use/cli.ts +8 -0
- package/src/computer-use/client.ts +81 -0
- package/src/computer-use/coords.ts +26 -0
- package/src/computer-use/history.ts +80 -0
- package/src/computer-use/index.ts +121 -0
- package/src/computer-use/keys.ts +54 -0
- package/src/computer-use/loop.ts +140 -0
- package/src/computer-use/safety.ts +59 -0
- package/src/computer-use/screenshot.ts +20 -0
- package/src/computer-use/system-prompt.ts +65 -0
- package/src/computer-use/types.ts +126 -0
- package/src/playwright/actions.ts +332 -0
- package/src/playwright/chromium.ts +30 -0
- package/src/playwright/index.ts +77 -0
- package/src/playwright/processed.ts +253 -0
- package/src/playwright/session.ts +220 -0
- package/src/shared/config.ts +320 -0
- package/src/shared/cost.ts +58 -0
- package/src/shared/logger.ts +9 -0
- package/src/shared/main-module.ts +20 -0
- package/src/shared/models.ts +62 -0
- package/src/shared/telemetry.ts +63 -0
package/README.md
ADDED
|
@@ -0,0 +1,169 @@
|
|
|
1
|
+
# @relauts/spotcheck-service
|
|
2
|
+
|
|
3
|
+
Local HTTP API that runs a Gemini computer-use agent in a Playwright Chromium session.
|
|
4
|
+
|
|
5
|
+
No UI. The server always binds to `127.0.0.1`. Callers send a Bearer token. You can save flows, replay them, and read run history.
|
|
6
|
+
|
|
7
|
+
License: AGPL-3.0-or-later. See [LICENSE](LICENSE) and [NOTICE](NOTICE).
|
|
8
|
+
|
|
9
|
+
## Install
|
|
10
|
+
|
|
11
|
+
```bash
|
|
12
|
+
npm install @relauts/spotcheck-service
|
|
13
|
+
npx playwright install chromium
|
|
14
|
+
```
|
|
15
|
+
|
|
16
|
+
Copy the example config into the folder where you will run the CLI:
|
|
17
|
+
|
|
18
|
+
```bash
|
|
19
|
+
cp node_modules/@relauts/spotcheck-service/relauts-spotcheck-service-config.example.json ./relauts-spotcheck-service-config.json
|
|
20
|
+
```
|
|
21
|
+
|
|
22
|
+
Set at least `apiToken` and `geminiApiKey`. Then:
|
|
23
|
+
|
|
24
|
+
```bash
|
|
25
|
+
npx spotcheck-service
|
|
26
|
+
```
|
|
27
|
+
|
|
28
|
+
The service listens on `http://127.0.0.1:18732` by default.
|
|
29
|
+
|
|
30
|
+
Config is read from `relauts-spotcheck-service-config.json` in the current working directory. If that file is missing, the service looks next to the package folder (git clone layout).
|
|
31
|
+
|
|
32
|
+
## Requirements
|
|
33
|
+
|
|
34
|
+
- Node.js `>=18.18.0`
|
|
35
|
+
- Chromium for Playwright: `npx playwright install chromium`
|
|
36
|
+
|
|
37
|
+
## From source
|
|
38
|
+
|
|
39
|
+
Config can also sit **next to this repo**, not inside it:
|
|
40
|
+
|
|
41
|
+
```
|
|
42
|
+
parent/
|
|
43
|
+
relauts-spotcheck-service/
|
|
44
|
+
relauts-spotcheck-service-config.json
|
|
45
|
+
```
|
|
46
|
+
|
|
47
|
+
```bash
|
|
48
|
+
cp relauts-spotcheck-service-config.example.json ../relauts-spotcheck-service-config.json
|
|
49
|
+
```
|
|
50
|
+
|
|
51
|
+
Set at least `apiToken` and `geminiApiKey`. Do not commit the real config file.
|
|
52
|
+
|
|
53
|
+
```bash
|
|
54
|
+
npm install
|
|
55
|
+
npx playwright install chromium
|
|
56
|
+
npm run dev
|
|
57
|
+
```
|
|
58
|
+
|
|
59
|
+
Or:
|
|
60
|
+
|
|
61
|
+
```bash
|
|
62
|
+
npm start
|
|
63
|
+
```
|
|
64
|
+
|
|
65
|
+
CLI after build: `spotcheck-service`.
|
|
66
|
+
|
|
67
|
+
## Auth
|
|
68
|
+
|
|
69
|
+
All `/v1/*` routes require:
|
|
70
|
+
|
|
71
|
+
```http
|
|
72
|
+
Authorization: Bearer <apiToken>
|
|
73
|
+
```
|
|
74
|
+
|
|
75
|
+
Exception: `GET /v1/health` (no auth).
|
|
76
|
+
|
|
77
|
+
Token compare uses SHA-256 digests + `timingSafeEqual`.
|
|
78
|
+
|
|
79
|
+
## Endpoints
|
|
80
|
+
|
|
81
|
+
| Method | Path | Auth | Body / notes |
|
|
82
|
+
|---|---|---|---|
|
|
83
|
+
| `GET` | `/v1/health` | no | `{ "ok": true }` |
|
|
84
|
+
| `GET` | `/v1/models` | yes | model list from `files/model.json` |
|
|
85
|
+
| `POST` | `/v1/agent` | yes | `{ "task", "model" }` → NDJSON stream |
|
|
86
|
+
| `POST` | `/v1/agent/safety` | yes | `{ "id", "confirmed" }` |
|
|
87
|
+
| `GET` | `/v1/session` | yes | `{ "open", "url" }` |
|
|
88
|
+
| `POST` | `/v1/session/back` | yes | navigate back |
|
|
89
|
+
| `POST` | `/v1/session/forward` | yes | navigate forward |
|
|
90
|
+
| `POST` | `/v1/session/reload` | yes | reload |
|
|
91
|
+
| `GET` | `/v1/screenshot` | yes | `{ "imageName": "..." }` |
|
|
92
|
+
| `GET` | `/v1/saved` | yes | `{ "files": [...] }` |
|
|
93
|
+
| `GET` | `/v1/saved/running` | yes | `{ "files": [...] }` currently running saved runs |
|
|
94
|
+
| `POST` | `/v1/saved` | yes | `{ "fileName", "items" }` |
|
|
95
|
+
| `GET` | `/v1/saved/:fileName` | yes | saved flow |
|
|
96
|
+
| `PUT` | `/v1/saved/:fileName` | yes | `{ "items" }` |
|
|
97
|
+
| `DELETE` | `/v1/saved/:fileName` | yes | delete |
|
|
98
|
+
| `GET` | `/v1/saved/create-default.json` | yes | create-tab default |
|
|
99
|
+
| `PUT` | `/v1/saved/create-default.json` | yes | `{ "items" }` |
|
|
100
|
+
| `GET` | `/v1/history` | yes | `{ "runs": [{ "historyFile", "status" }] }` all history runs |
|
|
101
|
+
| `POST` | `/v1/history/detail` | yes | `{ "historyFile" }` prompts, results, models, screenshots |
|
|
102
|
+
| `POST` | `/v1/saved/run` | yes | `{ "fileName" }` start a saved run |
|
|
103
|
+
| `POST` | `/v1/history/status` | yes | `{ "fileName" }` latest run status |
|
|
104
|
+
| `POST` | `/v1/history/stop` | yes | `{ "fileName" }` stop latest run |
|
|
105
|
+
|
|
106
|
+
Errors: `{ "error": "message" }` with HTTP status.
|
|
107
|
+
|
|
108
|
+
Agent NDJSON events match the original Spotcheck UI contract (`intent`, `safety_confirm`, `done`, `error`).
|
|
109
|
+
|
|
110
|
+
Full request and response shapes: [openapi.yaml](openapi.yaml).
|
|
111
|
+
|
|
112
|
+
## Curl examples
|
|
113
|
+
|
|
114
|
+
Health:
|
|
115
|
+
|
|
116
|
+
```bash
|
|
117
|
+
curl -s http://127.0.0.1:18732/v1/health
|
|
118
|
+
```
|
|
119
|
+
|
|
120
|
+
Models:
|
|
121
|
+
|
|
122
|
+
```bash
|
|
123
|
+
curl -s http://127.0.0.1:18732/v1/models \
|
|
124
|
+
-H "Authorization: Bearer <apiToken>"
|
|
125
|
+
```
|
|
126
|
+
|
|
127
|
+
Screenshot:
|
|
128
|
+
|
|
129
|
+
```bash
|
|
130
|
+
curl -s http://127.0.0.1:18732/v1/screenshot \
|
|
131
|
+
-H "Authorization: Bearer <apiToken>"
|
|
132
|
+
```
|
|
133
|
+
|
|
134
|
+
Run agent:
|
|
135
|
+
|
|
136
|
+
```bash
|
|
137
|
+
curl -N http://127.0.0.1:18732/v1/agent \
|
|
138
|
+
-H "Authorization: Bearer <apiToken>" \
|
|
139
|
+
-H "Content-Type: application/json" \
|
|
140
|
+
-d '{"task":"go to https://example.com and check the page loads","model":"gemini-3.6-flash"}'
|
|
141
|
+
```
|
|
142
|
+
|
|
143
|
+
## CORS
|
|
144
|
+
|
|
145
|
+
Set `corsOrigins` in the config JSON to an allow list. No credentials. Preflight: `OPTIONS`.
|
|
146
|
+
|
|
147
|
+
## Develop
|
|
148
|
+
|
|
149
|
+
```bash
|
|
150
|
+
npm test
|
|
151
|
+
npm run typecheck
|
|
152
|
+
```
|
|
153
|
+
|
|
154
|
+
How to send a PR: [CONTRIBUTING.md](CONTRIBUTING.md).
|
|
155
|
+
|
|
156
|
+
Install from npm: `npm install @relauts/spotcheck-service`.
|
|
157
|
+
|
|
158
|
+
Local run data (`saved/`, `processed/`, `history/`) stays on disk and is gitignored.
|
|
159
|
+
|
|
160
|
+
## License
|
|
161
|
+
|
|
162
|
+
Spotcheck is free software: you can redistribute it and/or modify it under
|
|
163
|
+
the terms of the GNU Affero General Public License as published by the
|
|
164
|
+
Free Software Foundation, either version 3 of the License, or (at your
|
|
165
|
+
option) any later version.
|
|
166
|
+
|
|
167
|
+
See `LICENSE` and `NOTICE`.
|
|
168
|
+
|
|
169
|
+
The names Relauts and Spotcheck are trademarks of Relauts Pvt. Ltd.
|
|
@@ -0,0 +1,11 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Extracts the raw token from an Authorization header.
|
|
3
|
+
* Only the Bearer scheme is accepted.
|
|
4
|
+
*/
|
|
5
|
+
export declare function extractBearerToken(authorizationHeader: string | undefined): string | undefined;
|
|
6
|
+
/**
|
|
7
|
+
* Compares tokens in constant time by hashing both to fixed-length digests first.
|
|
8
|
+
* Avoids leaking token length via early return on Buffer length mismatch.
|
|
9
|
+
*/
|
|
10
|
+
export declare function tokensEqual(expected: string, provided: string): boolean;
|
|
11
|
+
export declare function isAuthorized(authorizationHeader: string | undefined, expectedToken: string): boolean;
|
package/dist/api/auth.js
ADDED
|
@@ -0,0 +1,32 @@
|
|
|
1
|
+
import { createHash, timingSafeEqual } from "node:crypto";
|
|
2
|
+
/**
|
|
3
|
+
* Extracts the raw token from an Authorization header.
|
|
4
|
+
* Only the Bearer scheme is accepted.
|
|
5
|
+
*/
|
|
6
|
+
export function extractBearerToken(authorizationHeader) {
|
|
7
|
+
if (!authorizationHeader) {
|
|
8
|
+
return undefined;
|
|
9
|
+
}
|
|
10
|
+
const match = /^Bearer\s+(\S+)\s*$/i.exec(authorizationHeader);
|
|
11
|
+
if (!match) {
|
|
12
|
+
return undefined;
|
|
13
|
+
}
|
|
14
|
+
return match[1];
|
|
15
|
+
}
|
|
16
|
+
/**
|
|
17
|
+
* Compares tokens in constant time by hashing both to fixed-length digests first.
|
|
18
|
+
* Avoids leaking token length via early return on Buffer length mismatch.
|
|
19
|
+
*/
|
|
20
|
+
export function tokensEqual(expected, provided) {
|
|
21
|
+
const expectedDigest = createHash("sha256").update(expected, "utf8").digest();
|
|
22
|
+
const providedDigest = createHash("sha256").update(provided, "utf8").digest();
|
|
23
|
+
return timingSafeEqual(expectedDigest, providedDigest);
|
|
24
|
+
}
|
|
25
|
+
export function isAuthorized(authorizationHeader, expectedToken) {
|
|
26
|
+
const provided = extractBearerToken(authorizationHeader);
|
|
27
|
+
if (provided === undefined) {
|
|
28
|
+
return false;
|
|
29
|
+
}
|
|
30
|
+
return tokensEqual(expectedToken, provided);
|
|
31
|
+
}
|
|
32
|
+
//# sourceMappingURL=auth.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"auth.js","sourceRoot":"","sources":["../../src/api/auth.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,UAAU,EAAE,eAAe,EAAE,MAAM,aAAa,CAAC;AAE1D;;;GAGG;AACH,MAAM,UAAU,kBAAkB,CAAC,mBAAuC;IACxE,IAAI,CAAC,mBAAmB,EAAE,CAAC;QACzB,OAAO,SAAS,CAAC;IACnB,CAAC;IAED,MAAM,KAAK,GAAG,sBAAsB,CAAC,IAAI,CAAC,mBAAmB,CAAC,CAAC;IAC/D,IAAI,CAAC,KAAK,EAAE,CAAC;QACX,OAAO,SAAS,CAAC;IACnB,CAAC;IAED,OAAO,KAAK,CAAC,CAAC,CAAC,CAAC;AAClB,CAAC;AAED;;;GAGG;AACH,MAAM,UAAU,WAAW,CAAC,QAAgB,EAAE,QAAgB;IAC5D,MAAM,cAAc,GAAG,UAAU,CAAC,QAAQ,CAAC,CAAC,MAAM,CAAC,QAAQ,EAAE,MAAM,CAAC,CAAC,MAAM,EAAE,CAAC;IAC9E,MAAM,cAAc,GAAG,UAAU,CAAC,QAAQ,CAAC,CAAC,MAAM,CAAC,QAAQ,EAAE,MAAM,CAAC,CAAC,MAAM,EAAE,CAAC;IAC9E,OAAO,eAAe,CAAC,cAAc,EAAE,cAAc,CAAC,CAAC;AACzD,CAAC;AAED,MAAM,UAAU,YAAY,CAC1B,mBAAuC,EACvC,aAAqB;IAErB,MAAM,QAAQ,GAAG,kBAAkB,CAAC,mBAAmB,CAAC,CAAC;IACzD,IAAI,QAAQ,KAAK,SAAS,EAAE,CAAC;QAC3B,OAAO,KAAK,CAAC;IACf,CAAC;IAED,OAAO,WAAW,CAAC,aAAa,EAAE,QAAQ,CAAC,CAAC;AAC9C,CAAC"}
|
|
@@ -0,0 +1,46 @@
|
|
|
1
|
+
import { type SavedPromptItem } from "./saved.js";
|
|
2
|
+
export declare const HISTORY_DIR: string;
|
|
3
|
+
export declare const HISTORY_RUN_STATUSES: readonly ["running", "done", "error", "stopped"];
|
|
4
|
+
export type HistoryRunStatus = (typeof HISTORY_RUN_STATUSES)[number];
|
|
5
|
+
export type HistoryItemStatus = "pending" | "running" | "done" | "error" | "skipped";
|
|
6
|
+
export interface HistoryRunSummary {
|
|
7
|
+
readonly historyFile: string;
|
|
8
|
+
readonly status: HistoryRunStatus;
|
|
9
|
+
}
|
|
10
|
+
export interface HistoryDetailItem {
|
|
11
|
+
readonly sequence: number;
|
|
12
|
+
readonly prompt: string;
|
|
13
|
+
readonly model: string;
|
|
14
|
+
readonly resultText?: string;
|
|
15
|
+
readonly screenshots: readonly string[];
|
|
16
|
+
}
|
|
17
|
+
export interface HistoryItem {
|
|
18
|
+
readonly sequence: number;
|
|
19
|
+
readonly id: string;
|
|
20
|
+
readonly prompt: string;
|
|
21
|
+
readonly model: string;
|
|
22
|
+
readonly status: HistoryItemStatus;
|
|
23
|
+
readonly resultText?: string;
|
|
24
|
+
readonly costUsd?: number;
|
|
25
|
+
readonly error?: string;
|
|
26
|
+
}
|
|
27
|
+
export interface HistoryDocument {
|
|
28
|
+
readonly fileName: string;
|
|
29
|
+
readonly status: HistoryRunStatus;
|
|
30
|
+
readonly current: number;
|
|
31
|
+
readonly total: number;
|
|
32
|
+
readonly items: readonly HistoryItem[];
|
|
33
|
+
}
|
|
34
|
+
export declare function makeHistoryFileName(savedFileName: string, now?: Date): string;
|
|
35
|
+
export declare function createHistoryDocument(savedFileName: string, items: readonly SavedPromptItem[]): HistoryDocument;
|
|
36
|
+
export declare function serializeHistoryDetailItem(item: HistoryItem, screenshots: readonly string[]): HistoryDetailItem;
|
|
37
|
+
export declare function serializeHistoryItem(item: HistoryItem): HistoryItem;
|
|
38
|
+
export declare function serializeHistoryDocument(document: HistoryDocument): HistoryDocument;
|
|
39
|
+
export declare function writeHistoryFile(historyFileName: string, document: HistoryDocument, directory?: string): Promise<string>;
|
|
40
|
+
export declare function readHistoryFile(historyFileName: string, directory?: string): Promise<HistoryDocument>;
|
|
41
|
+
export interface LatestHistoryMatch {
|
|
42
|
+
readonly historyFile: string;
|
|
43
|
+
readonly document: HistoryDocument;
|
|
44
|
+
}
|
|
45
|
+
export declare function listHistoryRuns(directory?: string): Promise<HistoryRunSummary[]>;
|
|
46
|
+
export declare function findLatestHistory(savedFileName: string, directory?: string): Promise<LatestHistoryMatch>;
|
|
@@ -0,0 +1,172 @@
|
|
|
1
|
+
import fs from "node:fs/promises";
|
|
2
|
+
import path from "node:path";
|
|
3
|
+
import { SavedNameError, SavedNotFoundError, normalizeSavedFileName } from "./saved.js";
|
|
4
|
+
export const HISTORY_DIR = path.resolve(process.cwd(), "history");
|
|
5
|
+
export const HISTORY_RUN_STATUSES = ["running", "done", "error", "stopped"];
|
|
6
|
+
function isHistoryRunStatus(value) {
|
|
7
|
+
return typeof value === "string" && HISTORY_RUN_STATUSES.includes(value);
|
|
8
|
+
}
|
|
9
|
+
export function makeHistoryFileName(savedFileName, now = new Date()) {
|
|
10
|
+
const name = normalizeSavedFileName(savedFileName);
|
|
11
|
+
const stem = name.slice(0, -".json".length);
|
|
12
|
+
const stamp = now.toISOString().replace(/[:.]/g, "-");
|
|
13
|
+
return `${stem}-${stamp}.json`;
|
|
14
|
+
}
|
|
15
|
+
export function createHistoryDocument(savedFileName, items) {
|
|
16
|
+
return {
|
|
17
|
+
fileName: normalizeSavedFileName(savedFileName),
|
|
18
|
+
status: "running",
|
|
19
|
+
current: 0,
|
|
20
|
+
total: items.length,
|
|
21
|
+
items: items.map((item) => ({
|
|
22
|
+
sequence: item.sequence,
|
|
23
|
+
id: item.id,
|
|
24
|
+
prompt: item.prompt,
|
|
25
|
+
model: item.model,
|
|
26
|
+
status: "pending",
|
|
27
|
+
})),
|
|
28
|
+
};
|
|
29
|
+
}
|
|
30
|
+
export function serializeHistoryDetailItem(item, screenshots) {
|
|
31
|
+
return {
|
|
32
|
+
sequence: item.sequence,
|
|
33
|
+
prompt: item.prompt,
|
|
34
|
+
model: item.model,
|
|
35
|
+
...(item.resultText ? { resultText: item.resultText } : {}),
|
|
36
|
+
screenshots: [...screenshots],
|
|
37
|
+
};
|
|
38
|
+
}
|
|
39
|
+
export function serializeHistoryItem(item) {
|
|
40
|
+
return {
|
|
41
|
+
sequence: item.sequence,
|
|
42
|
+
id: item.id,
|
|
43
|
+
prompt: item.prompt,
|
|
44
|
+
model: item.model,
|
|
45
|
+
status: item.status,
|
|
46
|
+
...(item.resultText ? { resultText: item.resultText } : {}),
|
|
47
|
+
...(typeof item.costUsd === "number" ? { costUsd: item.costUsd } : {}),
|
|
48
|
+
...(item.error ? { error: item.error } : {}),
|
|
49
|
+
};
|
|
50
|
+
}
|
|
51
|
+
export function serializeHistoryDocument(document) {
|
|
52
|
+
return {
|
|
53
|
+
fileName: document.fileName,
|
|
54
|
+
status: document.status,
|
|
55
|
+
current: document.current,
|
|
56
|
+
total: document.total,
|
|
57
|
+
items: document.items.map(serializeHistoryItem),
|
|
58
|
+
};
|
|
59
|
+
}
|
|
60
|
+
export async function writeHistoryFile(historyFileName, document, directory = HISTORY_DIR) {
|
|
61
|
+
const name = normalizeSavedFileName(historyFileName);
|
|
62
|
+
await fs.mkdir(directory, { recursive: true });
|
|
63
|
+
const body = `${JSON.stringify(serializeHistoryDocument(document), null, 2)}\n`;
|
|
64
|
+
const filePath = path.join(directory, name);
|
|
65
|
+
const tempPath = `${filePath}.${process.pid}.tmp`;
|
|
66
|
+
await fs.writeFile(tempPath, body);
|
|
67
|
+
await fs.rename(tempPath, filePath);
|
|
68
|
+
return name;
|
|
69
|
+
}
|
|
70
|
+
export async function readHistoryFile(historyFileName, directory = HISTORY_DIR) {
|
|
71
|
+
const name = normalizeSavedFileName(historyFileName);
|
|
72
|
+
const filePath = path.join(directory, name);
|
|
73
|
+
let raw;
|
|
74
|
+
try {
|
|
75
|
+
raw = await fs.readFile(filePath, "utf8");
|
|
76
|
+
}
|
|
77
|
+
catch (error) {
|
|
78
|
+
if (error.code === "ENOENT") {
|
|
79
|
+
throw new SavedNotFoundError(`History file not found: ${name}`);
|
|
80
|
+
}
|
|
81
|
+
throw error;
|
|
82
|
+
}
|
|
83
|
+
let parsed;
|
|
84
|
+
try {
|
|
85
|
+
parsed = JSON.parse(raw);
|
|
86
|
+
}
|
|
87
|
+
catch {
|
|
88
|
+
throw new SavedNameError("History file is not valid JSON");
|
|
89
|
+
}
|
|
90
|
+
if (typeof parsed !== "object" || parsed === null || Array.isArray(parsed)) {
|
|
91
|
+
throw new SavedNameError("History file must be a JSON object");
|
|
92
|
+
}
|
|
93
|
+
return parsed;
|
|
94
|
+
}
|
|
95
|
+
export async function listHistoryRuns(directory = HISTORY_DIR) {
|
|
96
|
+
let names;
|
|
97
|
+
try {
|
|
98
|
+
names = await fs.readdir(directory);
|
|
99
|
+
}
|
|
100
|
+
catch (error) {
|
|
101
|
+
if (error.code === "ENOENT") {
|
|
102
|
+
return [];
|
|
103
|
+
}
|
|
104
|
+
throw error;
|
|
105
|
+
}
|
|
106
|
+
const ranked = [];
|
|
107
|
+
for (const name of names) {
|
|
108
|
+
if (!name.toLowerCase().endsWith(".json")) {
|
|
109
|
+
continue;
|
|
110
|
+
}
|
|
111
|
+
try {
|
|
112
|
+
const document = await readHistoryFile(name, directory);
|
|
113
|
+
if (!isHistoryRunStatus(document.status)) {
|
|
114
|
+
continue;
|
|
115
|
+
}
|
|
116
|
+
const stats = await fs.stat(path.join(directory, name));
|
|
117
|
+
ranked.push({ historyFile: name, status: document.status, mtimeMs: stats.mtimeMs });
|
|
118
|
+
}
|
|
119
|
+
catch {
|
|
120
|
+
// Skip unreadable or invalid files.
|
|
121
|
+
}
|
|
122
|
+
}
|
|
123
|
+
ranked.sort((left, right) => {
|
|
124
|
+
if (right.mtimeMs !== left.mtimeMs) {
|
|
125
|
+
return right.mtimeMs - left.mtimeMs;
|
|
126
|
+
}
|
|
127
|
+
return right.historyFile.localeCompare(left.historyFile);
|
|
128
|
+
});
|
|
129
|
+
return ranked.map(({ historyFile, status }) => ({ historyFile, status }));
|
|
130
|
+
}
|
|
131
|
+
export async function findLatestHistory(savedFileName, directory = HISTORY_DIR) {
|
|
132
|
+
const wanted = normalizeSavedFileName(savedFileName);
|
|
133
|
+
let names;
|
|
134
|
+
try {
|
|
135
|
+
names = await fs.readdir(directory);
|
|
136
|
+
}
|
|
137
|
+
catch (error) {
|
|
138
|
+
if (error.code === "ENOENT") {
|
|
139
|
+
throw new SavedNotFoundError(`History file not found for: ${wanted}`);
|
|
140
|
+
}
|
|
141
|
+
throw error;
|
|
142
|
+
}
|
|
143
|
+
const ranked = [];
|
|
144
|
+
for (const name of names) {
|
|
145
|
+
if (!name.toLowerCase().endsWith(".json")) {
|
|
146
|
+
continue;
|
|
147
|
+
}
|
|
148
|
+
try {
|
|
149
|
+
const document = await readHistoryFile(name, directory);
|
|
150
|
+
if (normalizeSavedFileName(document.fileName) !== wanted) {
|
|
151
|
+
continue;
|
|
152
|
+
}
|
|
153
|
+
const stats = await fs.stat(path.join(directory, name));
|
|
154
|
+
ranked.push({ historyFile: name, document, mtimeMs: stats.mtimeMs });
|
|
155
|
+
}
|
|
156
|
+
catch {
|
|
157
|
+
// Skip unreadable or invalid files.
|
|
158
|
+
}
|
|
159
|
+
}
|
|
160
|
+
ranked.sort((left, right) => {
|
|
161
|
+
if (right.mtimeMs !== left.mtimeMs) {
|
|
162
|
+
return right.mtimeMs - left.mtimeMs;
|
|
163
|
+
}
|
|
164
|
+
return right.historyFile.localeCompare(left.historyFile);
|
|
165
|
+
});
|
|
166
|
+
const latest = ranked[0];
|
|
167
|
+
if (!latest) {
|
|
168
|
+
throw new SavedNotFoundError(`History file not found for: ${wanted}`);
|
|
169
|
+
}
|
|
170
|
+
return { historyFile: latest.historyFile, document: latest.document };
|
|
171
|
+
}
|
|
172
|
+
//# sourceMappingURL=history.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"history.js","sourceRoot":"","sources":["../../src/api/history.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,35 @@
|
|
|
1
|
+
import { type AgentRunExtras, type AgentRunResult } from "../computer-use/index.js";
|
|
2
|
+
import { type BrowserSession } from "../playwright/session.js";
|
|
3
|
+
import type { AppConfig } from "../shared/config.js";
|
|
4
|
+
import { type AutomationReporter } from "../shared/telemetry.js";
|
|
5
|
+
export declare class SavedRunBusyError extends Error {
|
|
6
|
+
constructor(message?: string);
|
|
7
|
+
}
|
|
8
|
+
export declare class SavedRunLimitError extends Error {
|
|
9
|
+
constructor(message?: string);
|
|
10
|
+
}
|
|
11
|
+
export declare class SavedRunNotRunningError extends Error {
|
|
12
|
+
constructor(message?: string);
|
|
13
|
+
}
|
|
14
|
+
export declare class SavedRunFinishedError extends Error {
|
|
15
|
+
constructor(message?: string);
|
|
16
|
+
}
|
|
17
|
+
export type SavedRunTask = (task: string, model: string, session: BrowserSession, extras?: AgentRunExtras, screenshotDir?: string) => Promise<AgentRunResult>;
|
|
18
|
+
export interface SavedRunManagerDeps {
|
|
19
|
+
readonly savedDir: string;
|
|
20
|
+
readonly historyDir: string;
|
|
21
|
+
readonly processedDir: string;
|
|
22
|
+
readonly config: AppConfig;
|
|
23
|
+
readonly runTask?: SavedRunTask;
|
|
24
|
+
readonly createSession?: (screenshotDir: string) => BrowserSession;
|
|
25
|
+
readonly now?: () => Date;
|
|
26
|
+
readonly reportAutomation?: AutomationReporter;
|
|
27
|
+
}
|
|
28
|
+
export declare function denySavedRunSafety(): Promise<boolean>;
|
|
29
|
+
export declare function createSavedRunManager(deps: SavedRunManagerDeps): {
|
|
30
|
+
start(savedFileName: string): Promise<string>;
|
|
31
|
+
stop(historyFileName: string): Promise<void>;
|
|
32
|
+
close(): Promise<void>;
|
|
33
|
+
listRunning(): string[];
|
|
34
|
+
};
|
|
35
|
+
export type SavedRunManager = ReturnType<typeof createSavedRunManager>;
|