captchakraken 2.8.0 → 3.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/AGENTS.md +112 -0
- package/NOTICE +36 -0
- package/dist/cli-invocation.d.ts +9 -40
- package/dist/cli-invocation.js +16 -49
- package/dist/errors.d.ts +7 -27
- package/dist/errors.js +6 -25
- package/dist/humanize.d.ts +56 -240
- package/dist/humanize.js +159 -415
- package/dist/index.d.ts +5 -129
- package/dist/index.js +4 -98
- package/dist/kinds.d.ts +135 -0
- package/dist/kinds.js +70 -0
- package/dist/limits.d.ts +0 -48
- package/dist/limits.js +2 -48
- package/dist/model-name.d.ts +4 -19
- package/dist/model-name.js +32 -40
- package/dist/playwright-types.d.ts +25 -95
- package/dist/playwright-types.js +0 -23
- package/dist/puppeteer-adapter.d.ts +4 -43
- package/dist/puppeteer-adapter.js +22 -58
- package/dist/python-command.d.ts +0 -41
- package/dist/python-command.js +0 -37
- package/dist/selectors.d.ts +54 -0
- package/dist/selectors.js +117 -0
- package/dist/slide-geometry.d.ts +2 -29
- package/dist/slide-geometry.js +18 -44
- package/dist/solver.d.ts +112 -539
- package/dist/solver.js +1088 -2950
- package/dist/timing.d.ts +7 -40
- package/dist/timing.js +4 -36
- package/dist/token-usage.d.ts +1 -7
- package/dist/token-usage.js +10 -95
- package/dist/types.d.ts +77 -483
- package/dist/watcher.d.ts +5 -78
- package/dist/watcher.js +0 -56
- package/package.json +12 -4
- package/python/AGENTS.md +122 -0
- package/python/NOTICE +36 -0
- package/python/README.md +1 -2
- package/python/examples/README.md +10 -0
- package/python/examples/_harness.py +4 -73
- package/python/examples/demoHcaptcha.py +0 -13
- package/python/examples/demoRecaptcha.py +0 -10
- package/python/examples/watch_playwright.py +1 -26
- package/python/examples/with_local_gguf.py +28 -0
- package/python/examples/with_playwright.py +0 -19
- package/python/pyproject.toml +68 -19
- package/python/src/captchakraken/__init__.py +37 -45
- package/python/src/captchakraken/action_types.py +14 -36
- package/python/src/captchakraken/cli.py +262 -879
- package/python/src/captchakraken/config.py +60 -146
- package/python/src/captchakraken/errors.py +17 -95
- package/python/src/captchakraken/humanize.py +174 -597
- package/python/src/captchakraken/image_processor.py +16 -235
- package/python/src/captchakraken/keyframes.py +69 -434
- package/python/src/captchakraken/kinds.py +152 -0
- package/python/src/captchakraken/models.json +79 -21
- package/python/src/captchakraken/overlay.py +65 -498
- package/python/src/captchakraken/page_solver.py +1123 -2564
- package/python/src/captchakraken/planner.py +70 -428
- package/python/src/captchakraken/prompts.py +45 -261
- package/python/src/captchakraken/selectors.py +184 -0
- package/python/src/captchakraken/server_manager.py +7 -58
- package/python/src/captchakraken/solver.py +128 -522
- package/python/src/captchakraken/timing.py +20 -74
- package/python/src/captchakraken/tool_calls/board_painted.py +47 -0
- package/python/src/captchakraken/tool_calls/find_checkbox.py +20 -30
- package/python/src/captchakraken/tool_calls/find_grid.py +186 -1339
- package/python/src/captchakraken/tool_calls/track_piece.py +81 -57
- package/python/src/captchakraken/updater.py +7 -76
- package/python/src/captchakraken/watcher.py +12 -101
- package/scripts/copy-python.mjs +10 -10
- package/scripts/setup-python.js +1 -21
- package/dist/trajectory.d.ts +0 -58
- package/dist/trajectory.js +0 -266
- package/python/src/captchakraken/tool_calls/move_indicator.py +0 -431
- package/python/src/captchakraken/trajectory.py +0 -284
package/dist/timing.d.ts
CHANGED
|
@@ -1,48 +1,15 @@
|
|
|
1
|
-
|
|
2
|
-
|
|
3
|
-
*
|
|
4
|
-
* The TypeScript half of `python/src/captchakraken/timing.py`; the two are one
|
|
5
|
-
* implementation in two languages and `test_timing_parity.py` pins that they
|
|
6
|
-
* name the same phases. That parity is the point: without it the ports can only
|
|
7
|
-
* be compared on their totals, and "the JS port is four seconds slower" is not
|
|
8
|
-
* a bug report — "the JS port spends four seconds starting a Python
|
|
9
|
-
* interpreter it did not need to start" is.
|
|
10
|
-
*
|
|
11
|
-
* Always on. It is a few map updates per phase against multi-second waits, and
|
|
12
|
-
* a budget you have to opt into is one nobody has when the slow solve happens.
|
|
13
|
-
* Only PRINTED under `CAPTCHA_TIMINGS=1`; always RETURNED on `SolveResult`.
|
|
14
|
-
*/
|
|
15
|
-
/**
|
|
16
|
-
* What a phase's time COUNTS AS, when asking how much of a solve was useful.
|
|
17
|
-
*
|
|
18
|
-
* Only two kinds of second are worth spending: one the model is thinking in,
|
|
19
|
-
* and one the pointer is travelling in (which has to look human, so it cannot
|
|
20
|
-
* be rushed). Everything else is the driver waiting on a clock, and every such
|
|
21
|
-
* wait is a candidate for deletion or for overlapping with something real.
|
|
22
|
-
*/
|
|
23
|
-
export declare const PRODUCTIVE: Set<string>;
|
|
1
|
+
import { Phase } from './kinds.js';
|
|
2
|
+
export declare const PRODUCTIVE: ReadonlySet<Phase>;
|
|
24
3
|
export declare function timingsEnabled(): boolean;
|
|
4
|
+
/** Phases attribute, they do not partition: a nested phase counts under both names, and re-entering an open one counts once. */
|
|
25
5
|
export declare class PhaseBudget {
|
|
26
|
-
readonly totals: Map<
|
|
27
|
-
readonly counts: Map<
|
|
6
|
+
readonly totals: Map<Phase, number>;
|
|
7
|
+
readonly counts: Map<Phase, number>;
|
|
28
8
|
private readonly open;
|
|
29
9
|
private readonly t0;
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
*
|
|
33
|
-
* Phases may nest (a burst contains its screenshots). Only the OUTERMOST of a
|
|
34
|
-
* given NAME accumulates, so re-entering one cannot double-count it — but a
|
|
35
|
-
* phase nested inside a differently-named one counts under both, deliberately:
|
|
36
|
-
* the cursor drifting over the widget WHILE the model generates is genuinely
|
|
37
|
-
* both `mouse` and `inference`, and hiding either would misreport what the
|
|
38
|
-
* solve was doing. The totals are therefore an attribution, not a partition,
|
|
39
|
-
* and can exceed the elapsed time.
|
|
40
|
-
*/
|
|
41
|
-
phase<T>(name: string, fn: () => Promise<T>): Promise<T>;
|
|
42
|
-
/** Record a measured span directly, for blocks that would need re-indenting. */
|
|
43
|
-
add(name: string, ms: number): void;
|
|
10
|
+
phase<T>(name: Phase, fn: () => Promise<T>): Promise<T>;
|
|
11
|
+
add(name: Phase, ms: number): void;
|
|
44
12
|
elapsedMs(): number;
|
|
45
|
-
/** Plain object for `SolveResult.phases`, with the solve total folded in. */
|
|
46
13
|
toObject(): Record<string, number>;
|
|
47
14
|
report(): string;
|
|
48
15
|
}
|
package/dist/timing.js
CHANGED
|
@@ -1,33 +1,14 @@
|
|
|
1
1
|
"use strict";
|
|
2
|
-
/**
|
|
3
|
-
* Where one solve's wall-clock went, by phase.
|
|
4
|
-
*
|
|
5
|
-
* The TypeScript half of `python/src/captchakraken/timing.py`; the two are one
|
|
6
|
-
* implementation in two languages and `test_timing_parity.py` pins that they
|
|
7
|
-
* name the same phases. That parity is the point: without it the ports can only
|
|
8
|
-
* be compared on their totals, and "the JS port is four seconds slower" is not
|
|
9
|
-
* a bug report — "the JS port spends four seconds starting a Python
|
|
10
|
-
* interpreter it did not need to start" is.
|
|
11
|
-
*
|
|
12
|
-
* Always on. It is a few map updates per phase against multi-second waits, and
|
|
13
|
-
* a budget you have to opt into is one nobody has when the slow solve happens.
|
|
14
|
-
* Only PRINTED under `CAPTCHA_TIMINGS=1`; always RETURNED on `SolveResult`.
|
|
15
|
-
*/
|
|
16
2
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
17
3
|
exports.PhaseBudget = exports.PRODUCTIVE = void 0;
|
|
18
4
|
exports.timingsEnabled = timingsEnabled;
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
* Only two kinds of second are worth spending: one the model is thinking in,
|
|
23
|
-
* and one the pointer is travelling in (which has to look human, so it cannot
|
|
24
|
-
* be rushed). Everything else is the driver waiting on a clock, and every such
|
|
25
|
-
* wait is a candidate for deletion or for overlapping with something real.
|
|
26
|
-
*/
|
|
27
|
-
exports.PRODUCTIVE = new Set(['inference', 'mouse']);
|
|
5
|
+
const kinds_js_1 = require("./kinds.js");
|
|
6
|
+
// Always collected, printed only under CAPTCHA_TIMINGS=1: a budget you have to opt into is one nobody has when the slow solve happens.
|
|
7
|
+
exports.PRODUCTIVE = new Set([kinds_js_1.Phase.INFERENCE, kinds_js_1.Phase.MOUSE]);
|
|
28
8
|
function timingsEnabled() {
|
|
29
9
|
return process.env.CAPTCHA_TIMINGS === '1';
|
|
30
10
|
}
|
|
11
|
+
/** Phases attribute, they do not partition: a nested phase counts under both names, and re-entering an open one counts once. */
|
|
31
12
|
class PhaseBudget {
|
|
32
13
|
constructor() {
|
|
33
14
|
this.totals = new Map();
|
|
@@ -35,17 +16,6 @@ class PhaseBudget {
|
|
|
35
16
|
this.open = [];
|
|
36
17
|
this.t0 = Date.now();
|
|
37
18
|
}
|
|
38
|
-
/**
|
|
39
|
-
* Attribute `fn`'s wall-clock to `name`.
|
|
40
|
-
*
|
|
41
|
-
* Phases may nest (a burst contains its screenshots). Only the OUTERMOST of a
|
|
42
|
-
* given NAME accumulates, so re-entering one cannot double-count it — but a
|
|
43
|
-
* phase nested inside a differently-named one counts under both, deliberately:
|
|
44
|
-
* the cursor drifting over the widget WHILE the model generates is genuinely
|
|
45
|
-
* both `mouse` and `inference`, and hiding either would misreport what the
|
|
46
|
-
* solve was doing. The totals are therefore an attribution, not a partition,
|
|
47
|
-
* and can exceed the elapsed time.
|
|
48
|
-
*/
|
|
49
19
|
async phase(name, fn) {
|
|
50
20
|
if (this.open.includes(name))
|
|
51
21
|
return fn();
|
|
@@ -59,7 +29,6 @@ class PhaseBudget {
|
|
|
59
29
|
this.add(name, Date.now() - t0);
|
|
60
30
|
}
|
|
61
31
|
}
|
|
62
|
-
/** Record a measured span directly, for blocks that would need re-indenting. */
|
|
63
32
|
add(name, ms) {
|
|
64
33
|
this.totals.set(name, (this.totals.get(name) ?? 0) + ms);
|
|
65
34
|
this.counts.set(name, (this.counts.get(name) ?? 0) + 1);
|
|
@@ -67,7 +36,6 @@ class PhaseBudget {
|
|
|
67
36
|
elapsedMs() {
|
|
68
37
|
return Date.now() - this.t0;
|
|
69
38
|
}
|
|
70
|
-
/** Plain object for `SolveResult.phases`, with the solve total folded in. */
|
|
71
39
|
toObject() {
|
|
72
40
|
const out = {};
|
|
73
41
|
for (const [k, v] of this.totals)
|
package/dist/token-usage.d.ts
CHANGED
|
@@ -1,11 +1,5 @@
|
|
|
1
1
|
import { TokenUsage } from './types';
|
|
2
|
-
|
|
3
|
-
inputPricePerM: number;
|
|
4
|
-
outputPricePerM: number;
|
|
5
|
-
cachedInputPricePerM: number;
|
|
6
|
-
}
|
|
7
|
-
export declare const PRICING: Record<string, ModelPricing>;
|
|
8
|
-
export declare function estimateCost(usage: TokenUsage): number;
|
|
2
|
+
/** One summed row for a solve. The client has no price list, so `estimatedCost` is always 0. */
|
|
9
3
|
export declare function aggregateTokenUsage(usages: TokenUsage[]): {
|
|
10
4
|
modelName: string;
|
|
11
5
|
inputTokens: number;
|
package/dist/token-usage.js
CHANGED
|
@@ -1,102 +1,17 @@
|
|
|
1
1
|
"use strict";
|
|
2
2
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
-
exports.PRICING = void 0;
|
|
4
|
-
exports.estimateCost = estimateCost;
|
|
5
3
|
exports.aggregateTokenUsage = aggregateTokenUsage;
|
|
6
|
-
|
|
7
|
-
|
|
8
|
-
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
},
|
|
12
|
-
'gemini-3-flash-preview': {
|
|
13
|
-
inputPricePerM: 0.50,
|
|
14
|
-
outputPricePerM: 3.00,
|
|
15
|
-
cachedInputPricePerM: 0.05,
|
|
16
|
-
},
|
|
17
|
-
'gemini-2.5-pro': {
|
|
18
|
-
inputPricePerM: 1.25,
|
|
19
|
-
outputPricePerM: 10.00,
|
|
20
|
-
cachedInputPricePerM: 0.125,
|
|
21
|
-
},
|
|
22
|
-
'gemini-2.5-flash': {
|
|
23
|
-
inputPricePerM: 0.30,
|
|
24
|
-
outputPricePerM: 2.50,
|
|
25
|
-
cachedInputPricePerM: 0.03,
|
|
26
|
-
},
|
|
27
|
-
'gemini-2.5-flash-preview': {
|
|
28
|
-
inputPricePerM: 0.30,
|
|
29
|
-
outputPricePerM: 2.50,
|
|
30
|
-
cachedInputPricePerM: 0.03,
|
|
31
|
-
},
|
|
32
|
-
'gemini-2.5-flash-lite': {
|
|
33
|
-
inputPricePerM: 0.10,
|
|
34
|
-
outputPricePerM: 0.40,
|
|
35
|
-
cachedInputPricePerM: 0.01,
|
|
36
|
-
},
|
|
37
|
-
'gemini-2.5-flash-lite-preview': {
|
|
38
|
-
inputPricePerM: 0.10,
|
|
39
|
-
outputPricePerM: 0.40,
|
|
40
|
-
cachedInputPricePerM: 0.01,
|
|
41
|
-
},
|
|
42
|
-
'gemini-2.0-flash': {
|
|
43
|
-
inputPricePerM: 0.10,
|
|
44
|
-
outputPricePerM: 0.40,
|
|
45
|
-
cachedInputPricePerM: 0.025,
|
|
46
|
-
},
|
|
47
|
-
'gemini-2.5-computer-use-preview-10-2025': {
|
|
48
|
-
inputPricePerM: 1.25,
|
|
49
|
-
outputPricePerM: 10.00,
|
|
50
|
-
cachedInputPricePerM: 0.025,
|
|
51
|
-
}
|
|
52
|
-
};
|
|
53
|
-
// The CaptchaKraken CLI (vLLM/OpenAI shape) emits `prompt_tokens` /
|
|
54
|
-
// `completion_tokens`, while older Gemini-path usages used `input_tokens` /
|
|
55
|
-
// `output_tokens`. Normalize both so aggregation never produces NaN.
|
|
56
|
-
function inTok(u) {
|
|
57
|
-
return (u.input_tokens ?? u.prompt_tokens ?? 0);
|
|
58
|
-
}
|
|
59
|
-
function outTok(u) {
|
|
60
|
-
return (u.output_tokens ?? u.completion_tokens ?? 0);
|
|
61
|
-
}
|
|
62
|
-
function cachedTok(u) {
|
|
63
|
-
return (u.cached_input_tokens ?? u.prompt_tokens_details?.cached_tokens ?? 0);
|
|
64
|
-
}
|
|
65
|
-
function estimateCost(usage) {
|
|
66
|
-
const model = usage.model;
|
|
67
|
-
// Default to gemini-2.5-flash pricing if unknown
|
|
68
|
-
const pricing = exports.PRICING[model] || exports.PRICING['gemini-2.5-flash'];
|
|
69
|
-
const inputCost = (inTok(usage) / 1000000) * pricing.inputPricePerM;
|
|
70
|
-
const outputCost = (outTok(usage) / 1000000) * pricing.outputPricePerM;
|
|
71
|
-
const cachedCost = (cachedTok(usage) / 1000000) * pricing.cachedInputPricePerM;
|
|
72
|
-
return inputCost + outputCost + cachedCost;
|
|
73
|
-
}
|
|
4
|
+
// The CLI emits the vLLM/OpenAI shape (`prompt_tokens`); older rows used `input_tokens`.
|
|
5
|
+
const inTok = (u) => (u.input_tokens ?? u.prompt_tokens ?? 0);
|
|
6
|
+
const outTok = (u) => (u.output_tokens ?? u.completion_tokens ?? 0);
|
|
7
|
+
const cachedTok = (u) => (u.cached_input_tokens ?? u.prompt_tokens_details?.cached_tokens ?? 0);
|
|
8
|
+
/** One summed row for a solve. The client has no price list, so `estimatedCost` is always 0. */
|
|
74
9
|
function aggregateTokenUsage(usages) {
|
|
75
|
-
if (usages.length === 0) {
|
|
76
|
-
return {
|
|
77
|
-
modelName: 'none',
|
|
78
|
-
inputTokens: 0,
|
|
79
|
-
outputTokens: 0,
|
|
80
|
-
cachedInputTokens: 0,
|
|
81
|
-
estimatedCost: 0,
|
|
82
|
-
};
|
|
83
|
-
}
|
|
84
|
-
const modelName = usages[0].model;
|
|
85
|
-
let inputTokens = 0;
|
|
86
|
-
let outputTokens = 0;
|
|
87
|
-
let cachedInputTokens = 0;
|
|
88
|
-
let estimatedCost = 0;
|
|
89
|
-
for (const usage of usages) {
|
|
90
|
-
inputTokens += inTok(usage);
|
|
91
|
-
outputTokens += outTok(usage);
|
|
92
|
-
cachedInputTokens += cachedTok(usage);
|
|
93
|
-
estimatedCost += estimateCost(usage);
|
|
94
|
-
}
|
|
95
10
|
return {
|
|
96
|
-
modelName,
|
|
97
|
-
inputTokens,
|
|
98
|
-
outputTokens,
|
|
99
|
-
cachedInputTokens,
|
|
100
|
-
estimatedCost,
|
|
11
|
+
modelName: usages[0]?.model ?? 'none',
|
|
12
|
+
inputTokens: usages.reduce((n, u) => n + inTok(u), 0),
|
|
13
|
+
outputTokens: usages.reduce((n, u) => n + outTok(u), 0),
|
|
14
|
+
cachedInputTokens: usages.reduce((n, u) => n + cachedTok(u), 0),
|
|
15
|
+
estimatedCost: 0,
|
|
101
16
|
};
|
|
102
17
|
}
|