@browserbasehq/orca 3.1.0-patch.2 → 3.1.0-patch.3
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/dist/cjs/cli.js +45 -17
- package/dist/cjs/cli.js.map +2 -2
- package/dist/cjs/index.js +192 -123
- package/dist/cjs/index.js.map +3 -3
- package/dist/cjs/lib/logger.d.ts +1 -1
- package/dist/cjs/lib/modelUtils.d.ts +3 -0
- package/dist/cjs/lib/v3/agent/tools/act.d.ts +2 -1
- package/dist/cjs/lib/v3/agent/tools/extract.d.ts +2 -1
- package/dist/cjs/lib/v3/agent/tools/fillform.d.ts +2 -1
- package/dist/cjs/lib/v3/agent/tools/index.d.ts +2 -2
- package/dist/cjs/lib/v3/api.d.ts +16 -1
- package/dist/cjs/lib/v3/handlers/handlerUtils/actHandlerUtils.d.ts +0 -3
- package/dist/cjs/lib/v3/handlers/v3AgentHandler.d.ts +2 -2
- package/dist/cjs/lib/v3/tests/agent-callbacks.spec.js +12 -12
- package/dist/cjs/lib/v3/tests/agent-callbacks.spec.js.map +1 -1
- package/dist/cjs/lib/v3/tests/context-addInitScript.spec.js +2 -2
- package/dist/cjs/lib/v3/tests/context-addInitScript.spec.js.map +1 -1
- package/dist/cjs/lib/v3/tests/locator-content-methods.spec.js +1 -0
- package/dist/cjs/lib/v3/tests/locator-content-methods.spec.js.map +1 -1
- package/dist/cjs/lib/v3/tests/locator-fill.spec.js +1 -0
- package/dist/cjs/lib/v3/tests/locator-fill.spec.js.map +1 -1
- package/dist/cjs/lib/v3/tests/locator-input-methods.spec.js +1 -0
- package/dist/cjs/lib/v3/tests/locator-input-methods.spec.js.map +1 -1
- package/dist/cjs/lib/v3/tests/locator-select-option.spec.js +1 -0
- package/dist/cjs/lib/v3/tests/locator-select-option.spec.js.map +1 -1
- package/dist/cjs/lib/v3/tests/page-addInitScript.spec.js +2 -2
- package/dist/cjs/lib/v3/tests/page-addInitScript.spec.js.map +1 -1
- package/dist/cjs/lib/v3/types/public/api.d.ts +8 -0
- package/dist/cjs/lib/v3/types/public/index.d.ts +1 -0
- package/dist/cjs/lib/v3/types/public/sdkErrors.d.ts +3 -0
- package/dist/cjs/tests/agent-execution-model.test.js +139 -0
- package/dist/cjs/tests/agent-execution-model.test.js.map +7 -0
- package/dist/cjs/tests/api-multiregion.test.js +73 -0
- package/dist/cjs/tests/api-multiregion.test.js.map +7 -0
- package/dist/cjs/tests/model-utils.test.js +43 -0
- package/dist/cjs/tests/model-utils.test.js.map +7 -0
- package/dist/cjs/tests/public-api/export-surface.test.js +1 -0
- package/dist/cjs/tests/public-api/export-surface.test.js.map +1 -1
- package/dist/cjs/tests/public-api/llm-and-agents.test.js +1 -0
- package/dist/cjs/tests/public-api/llm-and-agents.test.js.map +1 -1
- package/dist/cjs/tests/public-api/public-error-types.test.js +3 -1
- package/dist/cjs/tests/public-api/public-error-types.test.js.map +2 -2
- package/dist/cjs/tests/public-api/v3-core.test.js +1 -0
- package/dist/cjs/tests/public-api/v3-core.test.js.map +1 -1
- package/dist/cjs/tests/snapshot-capture-orchestration.test.js +2 -0
- package/dist/cjs/tests/snapshot-capture-orchestration.test.js.map +1 -1
- package/dist/cjs/tests/understudy-command-exception.test.js +52 -0
- package/dist/cjs/tests/understudy-command-exception.test.js.map +7 -0
- package/dist/esm/lib/logger.d.ts +1 -1
- package/dist/esm/lib/v3/cli.d.ts +2 -0
- package/dist/esm/lib/v3/cli.js +10 -0
- package/dist/esm/lib/v3/cli.js.map +1 -0
- package/dist/esm/lib/v3/dom/build/rerender-index.d.ts +0 -0
- package/dist/esm/lib/v3/dom/build/rerender-index.js.map +1 -0
- package/dist/esm/lib/v3/dom/build/v3-index.d.ts +0 -0
- package/dist/esm/lib/v3/dom/build/v3-index.js.map +1 -0
- package/dist/esm/lib/v3/index.d.ts +1 -0
- package/dist/esm/lib/v3/index.js +1 -0
- package/dist/esm/lib/v3/index.js.map +1 -1
- package/dist/esm/lib/v3/shutdown/supervisor.d.ts +7 -5
- package/dist/esm/lib/v3/shutdown/supervisor.js +93 -64
- package/dist/esm/lib/v3/shutdown/supervisor.js.map +1 -1
- package/dist/esm/lib/v3/shutdown/supervisorClient.js +49 -52
- package/dist/esm/lib/v3/shutdown/supervisorClient.js.map +1 -1
- package/dist/esm/lib/v3/tests/agent-callbacks.spec.js +12 -12
- package/dist/esm/lib/v3/tests/agent-callbacks.spec.js.map +1 -1
- package/dist/esm/lib/v3/tests/click-count.spec.js +47 -12
- package/dist/esm/lib/v3/tests/click-count.spec.js.map +2 -2
- package/dist/esm/lib/v3/tests/context-addInitScript.spec.js +2 -2
- package/dist/esm/lib/v3/tests/context-addInitScript.spec.js.map +1 -1
- package/dist/esm/lib/v3/tests/iframe-ctx-addInitScript.spec.js +67 -21
- package/dist/esm/lib/v3/tests/iframe-ctx-addInitScript.spec.js.map +2 -2
- package/dist/esm/lib/v3/tests/locator-content-methods.spec.js +1 -0
- package/dist/esm/lib/v3/tests/locator-content-methods.spec.js.map +1 -1
- package/dist/esm/lib/v3/tests/locator-fill.spec.js +1 -0
- package/dist/esm/lib/v3/tests/locator-fill.spec.js.map +1 -1
- package/dist/esm/lib/v3/tests/locator-input-methods.spec.js +1 -0
- package/dist/esm/lib/v3/tests/locator-input-methods.spec.js.map +1 -1
- package/dist/esm/lib/v3/tests/locator-select-option.spec.js +1 -0
- package/dist/esm/lib/v3/tests/locator-select-option.spec.js.map +1 -1
- package/dist/esm/lib/v3/tests/page-addInitScript.spec.js +2 -2
- package/dist/esm/lib/v3/tests/page-addInitScript.spec.js.map +1 -1
- package/dist/esm/lib/v3/tests/v3.playwright.config.js +3 -60
- package/dist/esm/lib/v3/tests/v3.playwright.config.js.map +2 -2
- package/dist/esm/lib/v3/types/private/shutdown.d.ts +1 -13
- package/dist/esm/lib/v3/types/private/shutdown.js.map +1 -1
- package/dist/esm/lib/v3/understudy/context.js +10 -1
- package/dist/esm/lib/v3/understudy/context.js.map +1 -1
- package/dist/esm/lib/v3/understudy/locator.js +2 -2
- package/dist/esm/lib/v3/understudy/locator.js.map +1 -1
- package/dist/esm/lib/v3/understudy/page.js +2 -1
- package/dist/esm/lib/v3/understudy/page.js.map +1 -1
- package/dist/esm/lib/v3/v3.js +2 -6
- package/dist/esm/lib/v3/v3.js.map +1 -1
- package/dist/esm/tests/public-api/export-surface.test.js +2 -0
- package/dist/esm/tests/public-api/export-surface.test.js.map +2 -2
- package/dist/esm/tests/public-api/llm-and-agents.test.js +1 -0
- package/dist/esm/tests/public-api/llm-and-agents.test.js.map +1 -1
- package/dist/esm/tests/public-api/public-error-types.test.js +1 -0
- package/dist/esm/tests/public-api/public-error-types.test.js.map +1 -1
- package/dist/esm/tests/public-api/v3-core.test.js +1 -0
- package/dist/esm/tests/public-api/v3-core.test.js.map +1 -1
- package/dist/esm/tests/snapshot-capture-orchestration.test.js +2 -0
- package/dist/esm/tests/snapshot-capture-orchestration.test.js.map +1 -1
- package/package.json +13 -11
- package/dist/esm/lib/v3/tests/envReporter.js +0 -57
- package/dist/esm/lib/v3/tests/envReporter.js.map +0 -7
|
@@ -0,0 +1,52 @@
|
|
|
1
|
+
var import_vitest = require("vitest");
|
|
2
|
+
var import_sdkErrors = require("../lib/v3/types/public/sdkErrors.js");
|
|
3
|
+
(0, import_vitest.describe)("UnderstudyCommandException", () => {
|
|
4
|
+
(0, import_vitest.it)("extends StagehandError", () => {
|
|
5
|
+
const err = new import_sdkErrors.UnderstudyCommandException("test");
|
|
6
|
+
(0, import_vitest.expect)(err).toBeInstanceOf(import_sdkErrors.StagehandError);
|
|
7
|
+
(0, import_vitest.expect)(err).toBeInstanceOf(Error);
|
|
8
|
+
});
|
|
9
|
+
(0, import_vitest.it)("has the correct name", () => {
|
|
10
|
+
const err = new import_sdkErrors.UnderstudyCommandException("test");
|
|
11
|
+
(0, import_vitest.expect)(err.name).toBe("UnderstudyCommandException");
|
|
12
|
+
});
|
|
13
|
+
(0, import_vitest.it)("preserves the message", () => {
|
|
14
|
+
const err = new import_sdkErrors.UnderstudyCommandException("something broke");
|
|
15
|
+
(0, import_vitest.expect)(err.message).toBe("something broke");
|
|
16
|
+
});
|
|
17
|
+
(0, import_vitest.it)("stores the original error as cause when provided", () => {
|
|
18
|
+
const original = new Error("root cause");
|
|
19
|
+
const err = new import_sdkErrors.UnderstudyCommandException("wrapper message", original);
|
|
20
|
+
(0, import_vitest.expect)(err.cause).toBe(original);
|
|
21
|
+
(0, import_vitest.expect)(err.cause.message).toBe("root cause");
|
|
22
|
+
(0, import_vitest.expect)(err.cause.stack).toBeDefined();
|
|
23
|
+
});
|
|
24
|
+
(0, import_vitest.it)("stores non-Error cause values", () => {
|
|
25
|
+
const err = new import_sdkErrors.UnderstudyCommandException("failed", "string cause");
|
|
26
|
+
(0, import_vitest.expect)(err.cause).toBe("string cause");
|
|
27
|
+
});
|
|
28
|
+
(0, import_vitest.it)("has undefined cause when none is provided", () => {
|
|
29
|
+
const err = new import_sdkErrors.UnderstudyCommandException("no cause");
|
|
30
|
+
(0, import_vitest.expect)(err.cause).toBeUndefined();
|
|
31
|
+
});
|
|
32
|
+
(0, import_vitest.it)("generates its own stack trace", () => {
|
|
33
|
+
const err = new import_sdkErrors.UnderstudyCommandException("test");
|
|
34
|
+
(0, import_vitest.expect)(err.stack).toBeDefined();
|
|
35
|
+
(0, import_vitest.expect)(err.stack).toContain("UnderstudyCommandException");
|
|
36
|
+
});
|
|
37
|
+
(0, import_vitest.it)("preserves the original stack via cause for debugging", () => {
|
|
38
|
+
function deepFunction() {
|
|
39
|
+
throw new Error("deep error");
|
|
40
|
+
}
|
|
41
|
+
let original;
|
|
42
|
+
try {
|
|
43
|
+
deepFunction();
|
|
44
|
+
} catch (e) {
|
|
45
|
+
original = e;
|
|
46
|
+
}
|
|
47
|
+
const wrapped = new import_sdkErrors.UnderstudyCommandException(original.message, original);
|
|
48
|
+
(0, import_vitest.expect)(wrapped.stack).toBeDefined();
|
|
49
|
+
(0, import_vitest.expect)(wrapped.cause.stack).toContain("deepFunction");
|
|
50
|
+
});
|
|
51
|
+
});
|
|
52
|
+
//# sourceMappingURL=understudy-command-exception.test.js.map
|
|
@@ -0,0 +1,7 @@
|
|
|
1
|
+
{
|
|
2
|
+
"version": 3,
|
|
3
|
+
"sources": ["../../../tests/understudy-command-exception.test.ts"],
|
|
4
|
+
"sourcesContent": ["import { describe, expect, it } from \"vitest\";\nimport {\n UnderstudyCommandException,\n StagehandError,\n} from \"../lib/v3/types/public/sdkErrors.js\";\n\ndescribe(\"UnderstudyCommandException\", () => {\n it(\"extends StagehandError\", () => {\n const err = new UnderstudyCommandException(\"test\");\n expect(err).toBeInstanceOf(StagehandError);\n expect(err).toBeInstanceOf(Error);\n });\n\n it(\"has the correct name\", () => {\n const err = new UnderstudyCommandException(\"test\");\n expect(err.name).toBe(\"UnderstudyCommandException\");\n });\n\n it(\"preserves the message\", () => {\n const err = new UnderstudyCommandException(\"something broke\");\n expect(err.message).toBe(\"something broke\");\n });\n\n it(\"stores the original error as cause when provided\", () => {\n const original = new Error(\"root cause\");\n const err = new UnderstudyCommandException(\"wrapper message\", original);\n\n expect(err.cause).toBe(original);\n expect((err.cause as Error).message).toBe(\"root cause\");\n expect((err.cause as Error).stack).toBeDefined();\n });\n\n it(\"stores non-Error cause values\", () => {\n const err = new UnderstudyCommandException(\"failed\", \"string cause\");\n expect(err.cause).toBe(\"string cause\");\n });\n\n it(\"has undefined cause when none is provided\", () => {\n const err = new UnderstudyCommandException(\"no cause\");\n expect(err.cause).toBeUndefined();\n });\n\n it(\"generates its own stack trace\", () => {\n const err = new UnderstudyCommandException(\"test\");\n expect(err.stack).toBeDefined();\n expect(err.stack).toContain(\"UnderstudyCommandException\");\n });\n\n it(\"preserves the original stack via cause for debugging\", () => {\n function deepFunction() {\n throw new Error(\"deep error\");\n }\n\n let original: Error;\n try {\n deepFunction();\n } catch (e) {\n original = e as Error;\n }\n\n const wrapped = new UnderstudyCommandException(original!.message, original);\n\n // The wrapper has its own stack\n expect(wrapped.stack).toBeDefined();\n // The original stack is accessible via cause\n expect((wrapped.cause as Error).stack).toContain(\"deepFunction\");\n });\n});\n"],
|
|
5
|
+
"mappings": "AAAA,oBAAqC;AACrC,uBAGO;AAAA,IAEP,wBAAS,8BAA8B,MAAM;AAC3C,wBAAG,0BAA0B,MAAM;AACjC,UAAM,MAAM,IAAI,4CAA2B,MAAM;AACjD,8BAAO,GAAG,EAAE,eAAe,+BAAc;AACzC,8BAAO,GAAG,EAAE,eAAe,KAAK;AAAA,EAClC,CAAC;AAED,wBAAG,wBAAwB,MAAM;AAC/B,UAAM,MAAM,IAAI,4CAA2B,MAAM;AACjD,8BAAO,IAAI,IAAI,EAAE,KAAK,4BAA4B;AAAA,EACpD,CAAC;AAED,wBAAG,yBAAyB,MAAM;AAChC,UAAM,MAAM,IAAI,4CAA2B,iBAAiB;AAC5D,8BAAO,IAAI,OAAO,EAAE,KAAK,iBAAiB;AAAA,EAC5C,CAAC;AAED,wBAAG,oDAAoD,MAAM;AAC3D,UAAM,WAAW,IAAI,MAAM,YAAY;AACvC,UAAM,MAAM,IAAI,4CAA2B,mBAAmB,QAAQ;AAEtE,8BAAO,IAAI,KAAK,EAAE,KAAK,QAAQ;AAC/B,8BAAQ,IAAI,MAAgB,OAAO,EAAE,KAAK,YAAY;AACtD,8BAAQ,IAAI,MAAgB,KAAK,EAAE,YAAY;AAAA,EACjD,CAAC;AAED,wBAAG,iCAAiC,MAAM;AACxC,UAAM,MAAM,IAAI,4CAA2B,UAAU,cAAc;AACnE,8BAAO,IAAI,KAAK,EAAE,KAAK,cAAc;AAAA,EACvC,CAAC;AAED,wBAAG,6CAA6C,MAAM;AACpD,UAAM,MAAM,IAAI,4CAA2B,UAAU;AACrD,8BAAO,IAAI,KAAK,EAAE,cAAc;AAAA,EAClC,CAAC;AAED,wBAAG,iCAAiC,MAAM;AACxC,UAAM,MAAM,IAAI,4CAA2B,MAAM;AACjD,8BAAO,IAAI,KAAK,EAAE,YAAY;AAC9B,8BAAO,IAAI,KAAK,EAAE,UAAU,4BAA4B;AAAA,EAC1D,CAAC;AAED,wBAAG,wDAAwD,MAAM;AAC/D,aAAS,eAAe;AACtB,YAAM,IAAI,MAAM,YAAY;AAAA,IAC9B;AAEA,QAAI;AACJ,QAAI;AACF,mBAAa;AAAA,IACf,SAAS,GAAG;AACV,iBAAW;AAAA,IACb;AAEA,UAAM,UAAU,IAAI,4CAA2B,SAAU,SAAS,QAAQ;AAG1E,8BAAO,QAAQ,KAAK,EAAE,YAAY;AAElC,8BAAQ,QAAQ,MAAgB,KAAK,EAAE,UAAU,cAAc;AAAA,EACjE,CAAC;AACH,CAAC;",
|
|
6
|
+
"names": []
|
|
7
|
+
}
|
package/dist/esm/lib/logger.d.ts
CHANGED
|
@@ -9,7 +9,7 @@ export interface LoggerOptions {
|
|
|
9
9
|
/**
|
|
10
10
|
* Creates a configured Pino logger instance
|
|
11
11
|
*/
|
|
12
|
-
export declare function createLogger(options?: LoggerOptions):
|
|
12
|
+
export declare function createLogger(options?: LoggerOptions): pino.Logger<never, boolean>;
|
|
13
13
|
/**
|
|
14
14
|
* StagehandLogger class that wraps Pino for our specific needs
|
|
15
15
|
*
|
|
@@ -0,0 +1,10 @@
|
|
|
1
|
+
#!/usr/bin/env node
|
|
2
|
+
import process from "node:process";
|
|
3
|
+
import { maybeRunShutdownSupervisorFromArgv } from "./shutdown/supervisor.js";
|
|
4
|
+
// currently the CLI is only used to spawn the shutdown supervisor
|
|
5
|
+
// in the future, we may want to add more CLI commands here
|
|
6
|
+
if (!maybeRunShutdownSupervisorFromArgv(process.argv.slice(2))) {
|
|
7
|
+
console.error("Unsupported stagehand CLI invocation. Expected --supervisor with valid args.");
|
|
8
|
+
process.exit(1);
|
|
9
|
+
}
|
|
10
|
+
//# sourceMappingURL=cli.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"cli.js","sourceRoot":"","sources":["../../../../lib/v3/cli.js"],"names":[],"mappings":";AAEA,OAAO,OAAO,MAAM,cAAc,CAAC;AACnC,OAAO,EAAE,kCAAkC,EAAE,MAAM,0BAA0B,CAAC;AAE9E,kEAAkE;AAClE,2DAA2D;AAC3D,IAAI,CAAC,kCAAkC,CAAC,OAAO,CAAC,IAAI,CAAC,KAAK,CAAC,CAAC,CAAC,CAAC,EAAE,CAAC;IAC/D,OAAO,CAAC,KAAK,CACX,8EAA8E,CAC/E,CAAC;IACF,OAAO,CAAC,IAAI,CAAC,CAAC,CAAC,CAAC;AAClB,CAAC","sourcesContent":["#!/usr/bin/env node\n\nimport process from \"node:process\";\nimport { maybeRunShutdownSupervisorFromArgv } from \"./shutdown/supervisor.js\";\n\n// currently the CLI is only used to spawn the shutdown supervisor\n// in the future, we may want to add more CLI commands here\nif (!maybeRunShutdownSupervisorFromArgv(process.argv.slice(2))) {\n console.error(\n \"Unsupported stagehand CLI invocation. Expected --supervisor with valid args.\",\n );\n process.exit(1);\n}\n"]}
|
|
File without changes
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"rerender-index.js","sourceRoot":"","sources":["../../../../../../lib/v3/dom/build/rerender-index.js"],"names":[],"mappings":"AAAA,CAAC,GAAE,EAAE,GAAC,SAAS,CAAC,KAAG,IAAG,CAAC;IAAA,IAAI,CAAC,GAAC,MAAM,CAAC,eAAe,CAAC;IAAA,IAAG,CAAC,CAAC,IAAE,OAAO,CAAC,CAAC,aAAa,IAAE,UAAU;QAAC,OAAO;IAAA,IAAI,CAAC,GAAC,EAAE,EAAC,CAAC,GAAC,QAAQ,CAAC,gBAAgB,CAAC,QAAQ,EAAC,UAAU,CAAC,YAAY,CAAC,CAAC;IAAA,OAAK,CAAC,CAAC,QAAQ,EAAE,GAAE,CAAC;QAAA,IAAI,CAAC,GAAC,CAAC,CAAC,WAAW,EAAC,CAAC,GAAC,CAAC,CAAC,OAAO,EAAE,WAAW,EAAE,IAAE,EAAE,CAAC;QAAA,IAAG,CAAC,CAAC,CAAC,QAAQ,CAAC,GAAG,CAAC,IAAE,OAAO,cAAc,EAAE,GAAG,IAAE,UAAU,IAAE,CAAC,cAAc,CAAC,GAAG,CAAC,CAAC,CAAC;YAAC,SAAS;QAAA,IAAI,CAAC,GAAC,CAAC,CAAC,CAAC,CAAC,UAAU,EAAC,CAAC,GAAC,CAAC,CAAC,CAAC,CAAC,aAAa,CAAC,CAAC,CAAC,CAAC;QAAA,CAAC,IAAE,CAAC,IAAE,CAAC,CAAC,IAAI,CAAC,CAAC,CAAC,CAAA;IAAA,CAAC;IAAA,KAAI,IAAI,CAAC,IAAI,CAAC;QAAC,IAAG,CAAC;YAAA,IAAI,CAAC,GAAC,CAAC,CAAC,SAAS,CAAC,CAAC,CAAC,CAAC,CAAC;YAAA,CAAC,CAAC,WAAW,CAAC,CAAC,CAAC,CAAA;QAAA,CAAC;QAAA,MAAK,CAAC,CAAA,CAAC;IAAA,CAAC,CAAC,KAAK,IAAE,CAAC,CAAC,MAAM,IAAE,OAAO,CAAC,IAAI,CAAC,uBAAuB,EAAC,EAAC,KAAK,EAAC,CAAC,CAAC,MAAM,EAAC,CAAC,CAAA;AAAA,CAAC;AAAA,OAAM,CAAC,EAAC,CAAC;IAAA,OAAO,CAAC,IAAI,CAAC,6BAA6B,EAAC,EAAC,OAAO,EAAC,MAAM,CAAC,CAAC,IAAE,EAAE,CAAC,EAAC,CAAC,CAAA;AAAA,CAAC,CAAA,CAAC,CAAA,CAAC,EAAE,CAAC,CAAA,CAAC,CAAC,EAAE,CAAC","sourcesContent":["(()=>{function s(){try{let o=window.__stagehandV3__;if(!o||typeof o.getClosedRoot!=\"function\")return;let t=[],r=document.createTreeWalker(document,NodeFilter.SHOW_ELEMENT);for(;r.nextNode();){let e=r.currentNode,n=e.tagName?.toLowerCase()??\"\";if(!n.includes(\"-\")||typeof customElements?.get!=\"function\"||!customElements.get(n))continue;let c=!!e.shadowRoot,i=!!o.getClosedRoot(e);c||i||t.push(e)}for(let e of t)try{let n=e.cloneNode(!0);e.replaceWith(n)}catch{}o.stats&&t.length&&console.info(\"[v3-piercer] rerender\",{count:t.length})}catch(o){console.info(\"[v3-piercer] rerender error\",{message:String(o??\"\")})}}s();})();\n"]}
|
|
File without changes
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"v3-index.js","sourceRoot":"","sources":["../../../../../../lib/v3/dom/build/v3-index.js"],"names":[],"mappings":"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","sourcesContent":["(()=>{function s(c={}){let r=e=>{let{hostToRoot:o}=e;window.__stagehandV3__={getClosedRoot:a=>o.get(a),stats:()=>({installed:!0,url:location.href,isTop:window.top===window,open:e.openCount,closed:e.closedCount})}},n=Element.prototype.attachShadow;if(n.__v3Patched&&n.__v3State){n.__v3State.debug=!0,r(n.__v3State);return}let t={hostToRoot:new WeakMap,openCount:0,closedCount:0,debug:!0},l=n,d=function(e){let o=e?.mode??\"open\",a=l.call(this,e);try{t.hostToRoot.set(this,a),o===\"closed\"?t.closedCount++:t.openCount++,t.debug&&console.info(\"[v3-piercer] attachShadow\",{tag:this.tagName?.toLowerCase()??\"\",mode:o,url:location.href})}catch{}return a};if(d.__v3Patched=!0,d.__v3State=t,Object.defineProperty(Element.prototype,\"attachShadow\",{configurable:!0,writable:!0,value:d}),c.tagExisting)try{let e=document.createTreeWalker(document,NodeFilter.SHOW_ELEMENT);for(;e.nextNode();){let o=e.currentNode;o.shadowRoot&&(t.hostToRoot.set(o,o.shadowRoot),t.openCount++)}}catch{}window.__stagehandV3Injected=!0,r(t),t.debug&&console.info(\"[v3-piercer] installed\",{url:location.href,isTop:window.top===window,readyState:document.readyState})}s({debug:!0,tagExisting:!1});})();\n"]}
|
|
@@ -11,6 +11,7 @@ export { V3Evaluator } from "../v3Evaluator.js";
|
|
|
11
11
|
export { tool } from "ai";
|
|
12
12
|
export { getAISDKLanguageModel } from "./llm/LLMProvider.js";
|
|
13
13
|
export { __internalCreateInMemoryAgentCacheHandle } from "./cache/serverAgentCache.js";
|
|
14
|
+
export { maybeRunShutdownSupervisorFromArgv as __internalMaybeRunShutdownSupervisorFromArgv } from "./shutdown/supervisor.js";
|
|
14
15
|
export type { ServerAgentCacheHandle } from "./cache/serverAgentCache.js";
|
|
15
16
|
export type { ChatMessage, ChatMessageContent, ChatMessageImageContent, ChatMessageTextContent, ChatCompletionOptions, LLMResponse, CreateChatCompletionOptions, LLMUsage, LLMParsedResponse, } from "./llm/LLMClient.js";
|
|
16
17
|
export type { StagehandZodSchema, StagehandZodObject, InferStagehandSchema, JsonSchemaDocument, } from "./zodCompat.js";
|
package/dist/esm/lib/v3/index.js
CHANGED
|
@@ -10,4 +10,5 @@ export { V3Evaluator } from "../v3Evaluator.js";
|
|
|
10
10
|
export { tool } from "ai";
|
|
11
11
|
export { getAISDKLanguageModel } from "./llm/LLMProvider.js";
|
|
12
12
|
export { __internalCreateInMemoryAgentCacheHandle } from "./cache/serverAgentCache.js";
|
|
13
|
+
export { maybeRunShutdownSupervisorFromArgv as __internalMaybeRunShutdownSupervisorFromArgv } from "./shutdown/supervisor.js";
|
|
13
14
|
//# sourceMappingURL=index.js.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"index.js","sourceRoot":"","sources":["../../../../lib/v3/index.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,EAAE,EAAE,MAAM,SAAS,CAAC;AAC7B,OAAO,EAAE,EAAE,IAAI,SAAS,EAAE,MAAM,SAAS,CAAC;AAE1C,cAAc,yBAAyB,CAAC;AACxC,OAAO,EAAE,uBAAuB,EAAE,SAAS,EAAE,MAAM,oBAAoB,CAAC;AAExE,OAAO,EACL,aAAa,EACb,uBAAuB,GACxB,MAAM,0BAA0B,CAAC;AASlC,OAAO,EACL,iBAAiB,EACjB,cAAc,EACd,cAAc,EACd,UAAU,EACV,eAAe,EACf,UAAU,EACV,iBAAiB,EACjB,iBAAiB,EACjB,oBAAoB,EACpB,eAAe,GAChB,MAAM,aAAa,CAAC;AACrB,OAAO,EAAE,YAAY,EAAE,YAAY,EAAE,YAAY,EAAE,MAAM,gBAAgB,CAAC;AAE1E,OAAO,EAAE,kBAAkB,EAAE,MAAM,qBAAqB,CAAC;AACzD,OAAO,EAAE,WAAW,EAAE,MAAM,mBAAmB,CAAC;AAChD,OAAO,EAAE,IAAI,EAAE,MAAM,IAAI,CAAC;AAC1B,OAAO,EAAE,qBAAqB,EAAE,MAAM,sBAAsB,CAAC;AAC7D,OAAO,EAAE,wCAAwC,EAAE,MAAM,6BAA6B,CAAC","sourcesContent":["export { V3 } from \"./v3.js\";\nexport { V3 as Stagehand } from \"./v3.js\";\n\nexport * from \"./types/public/index.js\";\nexport { AnnotatedScreenshotText, LLMClient } from \"./llm/LLMClient.js\";\n\nexport {\n AgentProvider,\n modelToAgentProviderMap,\n} from \"./agent/AgentProvider.js\";\nexport type {\n AgentTools,\n AgentToolTypesMap,\n AgentUITools,\n AgentToolCall,\n AgentToolResult,\n} from \"./agent/tools/index.js\";\n\nexport {\n validateZodSchema,\n isRunningInBun,\n toGeminiSchema,\n getZodType,\n transformSchema,\n injectUrls,\n providerEnvVarMap,\n loadApiKeyFromEnv,\n trimTrailingTextNode,\n jsonSchemaToZod,\n} from \"../utils.js\";\nexport { isZod4Schema, isZod3Schema, toJsonSchema } from \"./zodCompat.js\";\n\nexport { connectToMCPServer } from \"./mcp/connection.js\";\nexport { V3Evaluator } from \"../v3Evaluator.js\";\nexport { tool } from \"ai\";\nexport { getAISDKLanguageModel } from \"./llm/LLMProvider.js\";\nexport { __internalCreateInMemoryAgentCacheHandle } from \"./cache/serverAgentCache.js\";\nexport type { ServerAgentCacheHandle } from \"./cache/serverAgentCache.js\";\n\nexport type {\n ChatMessage,\n ChatMessageContent,\n ChatMessageImageContent,\n ChatMessageTextContent,\n ChatCompletionOptions,\n LLMResponse,\n CreateChatCompletionOptions,\n LLMUsage,\n LLMParsedResponse,\n} from \"./llm/LLMClient.js\";\n\nexport type {\n StagehandZodSchema,\n StagehandZodObject,\n InferStagehandSchema,\n JsonSchemaDocument,\n} from \"./zodCompat.js\";\n\nexport type { JsonSchema, JsonSchemaProperty } from \"../utils.js\";\n"]}
|
|
1
|
+
{"version":3,"file":"index.js","sourceRoot":"","sources":["../../../../lib/v3/index.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,EAAE,EAAE,MAAM,SAAS,CAAC;AAC7B,OAAO,EAAE,EAAE,IAAI,SAAS,EAAE,MAAM,SAAS,CAAC;AAE1C,cAAc,yBAAyB,CAAC;AACxC,OAAO,EAAE,uBAAuB,EAAE,SAAS,EAAE,MAAM,oBAAoB,CAAC;AAExE,OAAO,EACL,aAAa,EACb,uBAAuB,GACxB,MAAM,0BAA0B,CAAC;AASlC,OAAO,EACL,iBAAiB,EACjB,cAAc,EACd,cAAc,EACd,UAAU,EACV,eAAe,EACf,UAAU,EACV,iBAAiB,EACjB,iBAAiB,EACjB,oBAAoB,EACpB,eAAe,GAChB,MAAM,aAAa,CAAC;AACrB,OAAO,EAAE,YAAY,EAAE,YAAY,EAAE,YAAY,EAAE,MAAM,gBAAgB,CAAC;AAE1E,OAAO,EAAE,kBAAkB,EAAE,MAAM,qBAAqB,CAAC;AACzD,OAAO,EAAE,WAAW,EAAE,MAAM,mBAAmB,CAAC;AAChD,OAAO,EAAE,IAAI,EAAE,MAAM,IAAI,CAAC;AAC1B,OAAO,EAAE,qBAAqB,EAAE,MAAM,sBAAsB,CAAC;AAC7D,OAAO,EAAE,wCAAwC,EAAE,MAAM,6BAA6B,CAAC;AACvF,OAAO,EAAE,kCAAkC,IAAI,4CAA4C,EAAE,MAAM,0BAA0B,CAAC","sourcesContent":["export { V3 } from \"./v3.js\";\nexport { V3 as Stagehand } from \"./v3.js\";\n\nexport * from \"./types/public/index.js\";\nexport { AnnotatedScreenshotText, LLMClient } from \"./llm/LLMClient.js\";\n\nexport {\n AgentProvider,\n modelToAgentProviderMap,\n} from \"./agent/AgentProvider.js\";\nexport type {\n AgentTools,\n AgentToolTypesMap,\n AgentUITools,\n AgentToolCall,\n AgentToolResult,\n} from \"./agent/tools/index.js\";\n\nexport {\n validateZodSchema,\n isRunningInBun,\n toGeminiSchema,\n getZodType,\n transformSchema,\n injectUrls,\n providerEnvVarMap,\n loadApiKeyFromEnv,\n trimTrailingTextNode,\n jsonSchemaToZod,\n} from \"../utils.js\";\nexport { isZod4Schema, isZod3Schema, toJsonSchema } from \"./zodCompat.js\";\n\nexport { connectToMCPServer } from \"./mcp/connection.js\";\nexport { V3Evaluator } from \"../v3Evaluator.js\";\nexport { tool } from \"ai\";\nexport { getAISDKLanguageModel } from \"./llm/LLMProvider.js\";\nexport { __internalCreateInMemoryAgentCacheHandle } from \"./cache/serverAgentCache.js\";\nexport { maybeRunShutdownSupervisorFromArgv as __internalMaybeRunShutdownSupervisorFromArgv } from \"./shutdown/supervisor.js\";\nexport type { ServerAgentCacheHandle } from \"./cache/serverAgentCache.js\";\n\nexport type {\n ChatMessage,\n ChatMessageContent,\n ChatMessageImageContent,\n ChatMessageTextContent,\n ChatCompletionOptions,\n LLMResponse,\n CreateChatCompletionOptions,\n LLMUsage,\n LLMParsedResponse,\n} from \"./llm/LLMClient.js\";\n\nexport type {\n StagehandZodSchema,\n StagehandZodObject,\n InferStagehandSchema,\n JsonSchemaDocument,\n} from \"./zodCompat.js\";\n\nexport type { JsonSchema, JsonSchemaProperty } from \"../utils.js\";\n"]}
|
|
@@ -1,9 +1,11 @@
|
|
|
1
1
|
/**
|
|
2
2
|
* Shutdown supervisor process.
|
|
3
3
|
*
|
|
4
|
-
* This process watches a lifeline
|
|
5
|
-
*
|
|
6
|
-
* - LOCAL: kill Chrome + remove temp profile
|
|
7
|
-
* - STAGEHAND_API: request session release
|
|
4
|
+
* This process watches a stdin lifeline. When the parent dies, stdin closes
|
|
5
|
+
* and the supervisor performs best-effort cleanup:
|
|
6
|
+
* - LOCAL: kill Chrome + remove temp profile
|
|
7
|
+
* - STAGEHAND_API: request session release
|
|
8
8
|
*/
|
|
9
|
-
|
|
9
|
+
import type { ShutdownSupervisorConfig } from "../types/private/shutdown.js";
|
|
10
|
+
export declare const runShutdownSupervisor: (initialConfig: ShutdownSupervisorConfig) => void;
|
|
11
|
+
export declare const maybeRunShutdownSupervisorFromArgv: (argv?: readonly string[]) => boolean;
|
|
@@ -1,19 +1,21 @@
|
|
|
1
1
|
/**
|
|
2
2
|
* Shutdown supervisor process.
|
|
3
3
|
*
|
|
4
|
-
* This process watches a lifeline
|
|
5
|
-
*
|
|
6
|
-
* - LOCAL: kill Chrome + remove temp profile
|
|
7
|
-
* - STAGEHAND_API: request session release
|
|
4
|
+
* This process watches a stdin lifeline. When the parent dies, stdin closes
|
|
5
|
+
* and the supervisor performs best-effort cleanup:
|
|
6
|
+
* - LOCAL: kill Chrome + remove temp profile
|
|
7
|
+
* - STAGEHAND_API: request session release
|
|
8
8
|
*/
|
|
9
9
|
import Browserbase from "@browserbasehq/sdk";
|
|
10
10
|
import { cleanupLocalBrowser } from "./cleanupLocal.js";
|
|
11
|
-
const SIGKILL_POLL_MS =
|
|
12
|
-
const SIGKILL_TIMEOUT_MS =
|
|
11
|
+
const SIGKILL_POLL_MS = 250;
|
|
12
|
+
const SIGKILL_TIMEOUT_MS = 7_000;
|
|
13
13
|
const PID_POLL_INTERVAL_MS = 500;
|
|
14
|
-
|
|
14
|
+
// `cleanupPromise` guarantees we execute cleanup at most once.
|
|
15
15
|
let config = null;
|
|
16
16
|
let cleanupPromise = null;
|
|
17
|
+
let started = false;
|
|
18
|
+
let localPidKnownGone = false;
|
|
17
19
|
const exit = (code = 0) => {
|
|
18
20
|
try {
|
|
19
21
|
process.exit(code);
|
|
@@ -22,14 +24,18 @@ const exit = (code = 0) => {
|
|
|
22
24
|
// ignore
|
|
23
25
|
}
|
|
24
26
|
};
|
|
25
|
-
|
|
27
|
+
// Best-effort two-phase kill: SIGTERM first, then SIGKILL after timeout.
|
|
28
|
+
// Treat only ESRCH as "already gone"; other errors should not imply dead.
|
|
29
|
+
const politeKill = async (pid) => {
|
|
26
30
|
const isAlive = () => {
|
|
27
31
|
try {
|
|
28
32
|
process.kill(pid, 0);
|
|
29
33
|
return true;
|
|
30
34
|
}
|
|
31
|
-
catch {
|
|
32
|
-
|
|
35
|
+
catch (error) {
|
|
36
|
+
const err = error;
|
|
37
|
+
// ESRCH = "No such process" (PID is already gone).
|
|
38
|
+
return err.code !== "ESRCH";
|
|
33
39
|
}
|
|
34
40
|
};
|
|
35
41
|
if (!isAlive())
|
|
@@ -37,8 +43,11 @@ const safeKill = async (pid) => {
|
|
|
37
43
|
try {
|
|
38
44
|
process.kill(pid, "SIGTERM");
|
|
39
45
|
}
|
|
40
|
-
catch {
|
|
41
|
-
|
|
46
|
+
catch (error) {
|
|
47
|
+
const err = error;
|
|
48
|
+
// ESRCH = process already exited; no further action needed.
|
|
49
|
+
if (err.code === "ESRCH")
|
|
50
|
+
return;
|
|
42
51
|
}
|
|
43
52
|
const deadline = Date.now() + SIGKILL_TIMEOUT_MS;
|
|
44
53
|
while (Date.now() < deadline) {
|
|
@@ -53,40 +62,53 @@ const safeKill = async (pid) => {
|
|
|
53
62
|
// best-effort
|
|
54
63
|
}
|
|
55
64
|
};
|
|
56
|
-
let pidGone = false;
|
|
57
65
|
let pidPollTimer = null;
|
|
66
|
+
// Local-only fallback: if Chrome dies while parent still lives, run cleanup and exit.
|
|
58
67
|
const startPidPolling = (pid) => {
|
|
59
68
|
if (pidPollTimer)
|
|
60
69
|
return;
|
|
61
70
|
pidPollTimer = setInterval(() => {
|
|
62
71
|
try {
|
|
63
72
|
process.kill(pid, 0);
|
|
73
|
+
return;
|
|
64
74
|
}
|
|
65
|
-
catch {
|
|
66
|
-
|
|
67
|
-
|
|
68
|
-
|
|
69
|
-
|
|
70
|
-
|
|
75
|
+
catch (error) {
|
|
76
|
+
const err = error;
|
|
77
|
+
// Only ESRCH means the process is definitely gone.
|
|
78
|
+
if (err.code !== "ESRCH")
|
|
79
|
+
return;
|
|
80
|
+
}
|
|
81
|
+
localPidKnownGone = true;
|
|
82
|
+
if (pidPollTimer) {
|
|
83
|
+
clearInterval(pidPollTimer);
|
|
84
|
+
pidPollTimer = null;
|
|
71
85
|
}
|
|
86
|
+
void runCleanup("Browser process exited").finally(() => exit(0));
|
|
72
87
|
}, PID_POLL_INTERVAL_MS);
|
|
73
88
|
};
|
|
74
|
-
const cleanupLocal = async (cfg) => {
|
|
75
|
-
|
|
76
|
-
return;
|
|
89
|
+
const cleanupLocal = async (cfg, reason) => {
|
|
90
|
+
const deletingUserDataDir = Boolean(cfg.createdTempProfile && !cfg.preserveUserDataDir && cfg.userDataDir);
|
|
77
91
|
await cleanupLocalBrowser({
|
|
78
|
-
|
|
92
|
+
// If polling already observed ESRCH, avoid a follow-up PID kill.
|
|
93
|
+
// The PID could be reused by a different process before cleanup runs.
|
|
94
|
+
killChrome: cfg.pid && !localPidKnownGone
|
|
95
|
+
? () => {
|
|
96
|
+
console.error(`[shutdown-supervisor] Shutting down Chrome pid=${cfg.pid} ` +
|
|
97
|
+
`(reason=${reason}, deletingUserDataDir=${deletingUserDataDir})`);
|
|
98
|
+
return politeKill(cfg.pid);
|
|
99
|
+
}
|
|
100
|
+
: undefined,
|
|
79
101
|
userDataDir: cfg.userDataDir,
|
|
80
102
|
createdTempProfile: cfg.createdTempProfile,
|
|
81
103
|
preserveUserDataDir: cfg.preserveUserDataDir,
|
|
82
104
|
});
|
|
83
105
|
};
|
|
84
|
-
const cleanupBrowserbase = async (cfg) => {
|
|
85
|
-
if (cfg.keepAlive)
|
|
86
|
-
return;
|
|
106
|
+
const cleanupBrowserbase = async (cfg, reason) => {
|
|
87
107
|
if (!cfg.apiKey || !cfg.projectId || !cfg.sessionId)
|
|
88
108
|
return;
|
|
89
109
|
try {
|
|
110
|
+
console.error(`[shutdown-supervisor] Ending Browserbase session ${cfg.sessionId} ` +
|
|
111
|
+
`(reason=${reason})`);
|
|
90
112
|
const bb = new Browserbase({ apiKey: cfg.apiKey });
|
|
91
113
|
await bb.sessions.update(cfg.sessionId, {
|
|
92
114
|
status: "REQUEST_RELEASE",
|
|
@@ -97,60 +119,67 @@ const cleanupBrowserbase = async (cfg) => {
|
|
|
97
119
|
// best-effort cleanup
|
|
98
120
|
}
|
|
99
121
|
};
|
|
100
|
-
|
|
122
|
+
// Idempotent cleanup entrypoint used by all supervisor shutdown paths.
|
|
123
|
+
const runCleanup = (reason) => {
|
|
101
124
|
if (!cleanupPromise) {
|
|
102
125
|
cleanupPromise = (async () => {
|
|
103
126
|
const cfg = config;
|
|
104
|
-
if (!cfg
|
|
127
|
+
if (!cfg)
|
|
105
128
|
return;
|
|
106
|
-
armed = false;
|
|
107
129
|
if (cfg.kind === "LOCAL") {
|
|
108
|
-
await cleanupLocal(cfg);
|
|
130
|
+
await cleanupLocal(cfg, reason);
|
|
109
131
|
return;
|
|
110
132
|
}
|
|
111
133
|
if (cfg.kind === "STAGEHAND_API") {
|
|
112
|
-
await cleanupBrowserbase(cfg);
|
|
134
|
+
await cleanupBrowserbase(cfg, reason);
|
|
113
135
|
}
|
|
114
136
|
})();
|
|
115
137
|
}
|
|
116
138
|
return cleanupPromise;
|
|
117
139
|
};
|
|
118
|
-
const
|
|
119
|
-
|
|
140
|
+
const applyConfig = (nextConfig) => {
|
|
141
|
+
config = nextConfig;
|
|
142
|
+
localPidKnownGone = false;
|
|
143
|
+
if (config.kind === "LOCAL" && config.pid) {
|
|
144
|
+
startPidPolling(config.pid);
|
|
145
|
+
}
|
|
120
146
|
};
|
|
121
|
-
const
|
|
122
|
-
|
|
123
|
-
|
|
124
|
-
|
|
125
|
-
|
|
126
|
-
|
|
127
|
-
|
|
128
|
-
|
|
129
|
-
|
|
130
|
-
|
|
131
|
-
|
|
132
|
-
|
|
133
|
-
|
|
134
|
-
|
|
135
|
-
|
|
136
|
-
|
|
147
|
+
const onLifelineClosed = (reason) => {
|
|
148
|
+
void runCleanup(reason).finally(() => exit(0));
|
|
149
|
+
};
|
|
150
|
+
const parseConfigFromArgv = (argv = process.argv.slice(2)) => {
|
|
151
|
+
const prefix = "--supervisor-config=";
|
|
152
|
+
const raw = argv.find((arg) => arg.startsWith(prefix))?.slice(prefix.length);
|
|
153
|
+
if (!argv.includes("--supervisor") || !raw)
|
|
154
|
+
return null;
|
|
155
|
+
try {
|
|
156
|
+
return JSON.parse(raw);
|
|
157
|
+
}
|
|
158
|
+
catch {
|
|
159
|
+
return null;
|
|
160
|
+
}
|
|
161
|
+
};
|
|
162
|
+
export const runShutdownSupervisor = (initialConfig) => {
|
|
163
|
+
if (started)
|
|
137
164
|
return;
|
|
165
|
+
started = true;
|
|
166
|
+
applyConfig(initialConfig);
|
|
167
|
+
// Stdin is the lifeline; losing it means parent is gone.
|
|
168
|
+
try {
|
|
169
|
+
process.stdin.resume();
|
|
170
|
+
process.stdin.on("end", () => onLifelineClosed("Stagehand process completed"));
|
|
171
|
+
process.stdin.on("close", () => onLifelineClosed("Stagehand process completed"));
|
|
172
|
+
process.stdin.on("error", () => onLifelineClosed("Stagehand process crashed or was killed"));
|
|
138
173
|
}
|
|
139
|
-
|
|
140
|
-
|
|
141
|
-
exit(0);
|
|
174
|
+
catch {
|
|
175
|
+
// ignore
|
|
142
176
|
}
|
|
143
177
|
};
|
|
144
|
-
|
|
145
|
-
|
|
146
|
-
|
|
147
|
-
|
|
148
|
-
|
|
149
|
-
|
|
150
|
-
}
|
|
151
|
-
catch {
|
|
152
|
-
// ignore
|
|
153
|
-
}
|
|
154
|
-
process.on("disconnect", onLifelineClosed);
|
|
155
|
-
process.on("message", onMessage);
|
|
178
|
+
export const maybeRunShutdownSupervisorFromArgv = (argv = process.argv.slice(2)) => {
|
|
179
|
+
const parsed = parseConfigFromArgv(argv);
|
|
180
|
+
if (!parsed)
|
|
181
|
+
return false;
|
|
182
|
+
runShutdownSupervisor(parsed);
|
|
183
|
+
return true;
|
|
184
|
+
};
|
|
156
185
|
//# sourceMappingURL=supervisor.js.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"supervisor.js","sourceRoot":"","sources":["../../../../../lib/v3/shutdown/supervisor.ts"],"names":[],"mappings":"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","sourcesContent":["/**\n * Shutdown supervisor process.\n *\n * This process watches a lifeline (stdin/IPC). When the parent dies, the\n * lifeline closes and the supervisor performs best-effort cleanup:\n * - LOCAL: kill Chrome + remove temp profile (when keepAlive is false)\n * - STAGEHAND_API: request session release (when keepAlive is false)\n */\n\nimport Browserbase from \"@browserbasehq/sdk\";\nimport type {\n ShutdownSupervisorConfig,\n ShutdownSupervisorMessage,\n} from \"../types/private/shutdown.js\";\nimport { cleanupLocalBrowser } from \"./cleanupLocal.js\";\n\nconst SIGKILL_POLL_MS = 500;\nconst SIGKILL_TIMEOUT_MS = 10_000;\nconst PID_POLL_INTERVAL_MS = 500;\n\nlet armed = false;\nlet config: ShutdownSupervisorConfig | null = null;\nlet cleanupPromise: Promise<void> | null = null;\n\nconst exit = (code = 0): void => {\n try {\n process.exit(code);\n } catch {\n // ignore\n }\n};\n\nconst safeKill = async (pid: number): Promise<void> => {\n const isAlive = (): boolean => {\n try {\n process.kill(pid, 0);\n return true;\n } catch {\n return false;\n }\n };\n\n if (!isAlive()) return;\n try {\n process.kill(pid, \"SIGTERM\");\n } catch {\n return;\n }\n\n const deadline = Date.now() + SIGKILL_TIMEOUT_MS;\n while (Date.now() < deadline) {\n await new Promise((resolve) => setTimeout(resolve, SIGKILL_POLL_MS));\n if (!isAlive()) return;\n }\n try {\n process.kill(pid, \"SIGKILL\");\n } catch {\n // best-effort\n }\n};\n\nlet pidGone = false;\nlet pidPollTimer: NodeJS.Timeout | null = null;\n\nconst startPidPolling = (pid: number): void => {\n if (pidPollTimer) return;\n pidPollTimer = setInterval(() => {\n try {\n process.kill(pid, 0);\n } catch {\n pidGone = true;\n if (pidPollTimer) {\n clearInterval(pidPollTimer);\n pidPollTimer = null;\n }\n }\n }, PID_POLL_INTERVAL_MS);\n};\n\nconst cleanupLocal = async (\n cfg: Extract<ShutdownSupervisorConfig, { kind: \"LOCAL\" }>,\n) => {\n if (cfg.keepAlive) return;\n await cleanupLocalBrowser({\n killChrome: cfg.pid && !pidGone ? () => safeKill(cfg.pid) : undefined,\n userDataDir: cfg.userDataDir,\n createdTempProfile: cfg.createdTempProfile,\n preserveUserDataDir: cfg.preserveUserDataDir,\n });\n};\n\nconst cleanupBrowserbase = async (\n cfg: Extract<ShutdownSupervisorConfig, { kind: \"STAGEHAND_API\" }>,\n) => {\n if (cfg.keepAlive) return;\n if (!cfg.apiKey || !cfg.projectId || !cfg.sessionId) return;\n try {\n const bb = new Browserbase({ apiKey: cfg.apiKey });\n await bb.sessions.update(cfg.sessionId, {\n status: \"REQUEST_RELEASE\",\n projectId: cfg.projectId,\n });\n } catch {\n // best-effort cleanup\n }\n};\n\nconst runCleanup = (): Promise<void> => {\n if (!cleanupPromise) {\n cleanupPromise = (async () => {\n const cfg = config;\n if (!cfg || !armed) return;\n armed = false;\n if (cfg.kind === \"LOCAL\") {\n await cleanupLocal(cfg);\n return;\n }\n if (cfg.kind === \"STAGEHAND_API\") {\n await cleanupBrowserbase(cfg);\n }\n })();\n }\n return cleanupPromise;\n};\n\nconst onLifelineClosed = () => {\n void runCleanup().finally(() => exit(0));\n};\n\nconst onMessage = (raw: unknown) => {\n if (!raw || typeof raw !== \"object\") return;\n const msg = raw as ShutdownSupervisorMessage;\n if (msg.type === \"config\") {\n config = msg.config ?? null;\n armed = Boolean(config) && config?.keepAlive === false;\n if (armed && config?.kind === \"LOCAL\" && config?.pid) {\n startPidPolling(config.pid);\n }\n try {\n process.send?.({ type: \"ready\" });\n } catch {\n // ignore IPC failures\n }\n return;\n }\n if (msg.type === \"exit\") {\n armed = false;\n exit(0);\n }\n};\n\n// Keep stdin open as a lifeline to the parent process.\ntry {\n process.stdin.resume();\n process.stdin.on(\"end\", onLifelineClosed);\n process.stdin.on(\"close\", onLifelineClosed);\n process.stdin.on(\"error\", onLifelineClosed);\n} catch {\n // ignore\n}\n\nprocess.on(\"disconnect\", onLifelineClosed);\nprocess.on(\"message\", onMessage);\n"]}
|
|
1
|
+
{"version":3,"file":"supervisor.js","sourceRoot":"","sources":["../../../../../lib/v3/shutdown/supervisor.ts"],"names":[],"mappings":"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","sourcesContent":["/**\n * Shutdown supervisor process.\n *\n * This process watches a stdin lifeline. When the parent dies, stdin closes\n * and the supervisor performs best-effort cleanup:\n * - LOCAL: kill Chrome + remove temp profile\n * - STAGEHAND_API: request session release\n */\n\nimport Browserbase from \"@browserbasehq/sdk\";\nimport type { ShutdownSupervisorConfig } from \"../types/private/shutdown.js\";\nimport { cleanupLocalBrowser } from \"./cleanupLocal.js\";\n\nconst SIGKILL_POLL_MS = 250;\nconst SIGKILL_TIMEOUT_MS = 7_000;\nconst PID_POLL_INTERVAL_MS = 500;\n\n// `cleanupPromise` guarantees we execute cleanup at most once.\nlet config: ShutdownSupervisorConfig | null = null;\nlet cleanupPromise: Promise<void> | null = null;\nlet started = false;\nlet localPidKnownGone = false;\n\nconst exit = (code = 0): void => {\n try {\n process.exit(code);\n } catch {\n // ignore\n }\n};\n\n// Best-effort two-phase kill: SIGTERM first, then SIGKILL after timeout.\n// Treat only ESRCH as \"already gone\"; other errors should not imply dead.\nconst politeKill = async (pid: number): Promise<void> => {\n const isAlive = (): boolean => {\n try {\n process.kill(pid, 0);\n return true;\n } catch (error) {\n const err = error as NodeJS.ErrnoException;\n // ESRCH = \"No such process\" (PID is already gone).\n return err.code !== \"ESRCH\";\n }\n };\n\n if (!isAlive()) return;\n try {\n process.kill(pid, \"SIGTERM\");\n } catch (error) {\n const err = error as NodeJS.ErrnoException;\n // ESRCH = process already exited; no further action needed.\n if (err.code === \"ESRCH\") return;\n }\n\n const deadline = Date.now() + SIGKILL_TIMEOUT_MS;\n while (Date.now() < deadline) {\n await new Promise((resolve) => setTimeout(resolve, SIGKILL_POLL_MS));\n if (!isAlive()) return;\n }\n try {\n process.kill(pid, \"SIGKILL\");\n } catch {\n // best-effort\n }\n};\n\nlet pidPollTimer: NodeJS.Timeout | null = null;\n\n// Local-only fallback: if Chrome dies while parent still lives, run cleanup and exit.\nconst startPidPolling = (pid: number): void => {\n if (pidPollTimer) return;\n pidPollTimer = setInterval(() => {\n try {\n process.kill(pid, 0);\n return;\n } catch (error) {\n const err = error as NodeJS.ErrnoException;\n // Only ESRCH means the process is definitely gone.\n if (err.code !== \"ESRCH\") return;\n }\n\n localPidKnownGone = true;\n if (pidPollTimer) {\n clearInterval(pidPollTimer);\n pidPollTimer = null;\n }\n void runCleanup(\"Browser process exited\").finally(() => exit(0));\n }, PID_POLL_INTERVAL_MS);\n};\n\nconst cleanupLocal = async (\n cfg: Extract<ShutdownSupervisorConfig, { kind: \"LOCAL\" }>,\n reason: string,\n) => {\n const deletingUserDataDir = Boolean(\n cfg.createdTempProfile && !cfg.preserveUserDataDir && cfg.userDataDir,\n );\n await cleanupLocalBrowser({\n // If polling already observed ESRCH, avoid a follow-up PID kill.\n // The PID could be reused by a different process before cleanup runs.\n killChrome:\n cfg.pid && !localPidKnownGone\n ? () => {\n console.error(\n `[shutdown-supervisor] Shutting down Chrome pid=${cfg.pid} ` +\n `(reason=${reason}, deletingUserDataDir=${deletingUserDataDir})`,\n );\n return politeKill(cfg.pid);\n }\n : undefined,\n userDataDir: cfg.userDataDir,\n createdTempProfile: cfg.createdTempProfile,\n preserveUserDataDir: cfg.preserveUserDataDir,\n });\n};\n\nconst cleanupBrowserbase = async (\n cfg: Extract<ShutdownSupervisorConfig, { kind: \"STAGEHAND_API\" }>,\n reason: string,\n) => {\n if (!cfg.apiKey || !cfg.projectId || !cfg.sessionId) return;\n try {\n console.error(\n `[shutdown-supervisor] Ending Browserbase session ${cfg.sessionId} ` +\n `(reason=${reason})`,\n );\n const bb = new Browserbase({ apiKey: cfg.apiKey });\n await bb.sessions.update(cfg.sessionId, {\n status: \"REQUEST_RELEASE\",\n projectId: cfg.projectId,\n });\n } catch {\n // best-effort cleanup\n }\n};\n\n// Idempotent cleanup entrypoint used by all supervisor shutdown paths.\nconst runCleanup = (reason: string): Promise<void> => {\n if (!cleanupPromise) {\n cleanupPromise = (async () => {\n const cfg = config;\n if (!cfg) return;\n if (cfg.kind === \"LOCAL\") {\n await cleanupLocal(cfg, reason);\n return;\n }\n if (cfg.kind === \"STAGEHAND_API\") {\n await cleanupBrowserbase(cfg, reason);\n }\n })();\n }\n return cleanupPromise;\n};\n\nconst applyConfig = (nextConfig: ShutdownSupervisorConfig): void => {\n config = nextConfig;\n localPidKnownGone = false;\n if (config.kind === \"LOCAL\" && config.pid) {\n startPidPolling(config.pid);\n }\n};\n\nconst onLifelineClosed = (reason: string) => {\n void runCleanup(reason).finally(() => exit(0));\n};\n\nconst parseConfigFromArgv = (\n argv: readonly string[] = process.argv.slice(2),\n): ShutdownSupervisorConfig | null => {\n const prefix = \"--supervisor-config=\";\n const raw = argv.find((arg) => arg.startsWith(prefix))?.slice(prefix.length);\n if (!argv.includes(\"--supervisor\") || !raw) return null;\n try {\n return JSON.parse(raw) as ShutdownSupervisorConfig;\n } catch {\n return null;\n }\n};\n\nexport const runShutdownSupervisor = (\n initialConfig: ShutdownSupervisorConfig,\n): void => {\n if (started) return;\n started = true;\n applyConfig(initialConfig);\n\n // Stdin is the lifeline; losing it means parent is gone.\n try {\n process.stdin.resume();\n process.stdin.on(\"end\", () =>\n onLifelineClosed(\"Stagehand process completed\"),\n );\n process.stdin.on(\"close\", () =>\n onLifelineClosed(\"Stagehand process completed\"),\n );\n process.stdin.on(\"error\", () =>\n onLifelineClosed(\"Stagehand process crashed or was killed\"),\n );\n } catch {\n // ignore\n }\n};\n\nexport const maybeRunShutdownSupervisorFromArgv = (\n argv: readonly string[] = process.argv.slice(2),\n): boolean => {\n const parsed = parseConfigFromArgv(argv);\n if (!parsed) return false;\n runShutdownSupervisor(parsed);\n return true;\n};\n"]}
|
|
@@ -6,37 +6,67 @@
|
|
|
6
6
|
* session release) when keepAlive is false.
|
|
7
7
|
*/
|
|
8
8
|
import fs from "node:fs";
|
|
9
|
-
import path from "node:path";
|
|
10
9
|
import { spawn } from "node:child_process";
|
|
10
|
+
import { createRequire } from "node:module";
|
|
11
11
|
import { fileURLToPath } from "node:url";
|
|
12
12
|
import { ShutdownSupervisorResolveError, ShutdownSupervisorSpawnError, } from "../types/private/shutdownErrors.js";
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
const
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
|
|
13
|
+
// Resolve module path for both CJS and ESM builds.
|
|
14
|
+
const normalizedFilename = typeof __filename === "string" ? __filename.replaceAll("\\", "/") : "";
|
|
15
|
+
const hasAbsoluteFilename = normalizedFilename.startsWith("/") || /^[A-Za-z]:\//.test(normalizedFilename);
|
|
16
|
+
const modulePath = hasAbsoluteFilename
|
|
17
|
+
? __filename
|
|
18
|
+
: fileURLToPath(import.meta.url);
|
|
19
|
+
const normalizedModulePath = modulePath.replaceAll("\\", "/");
|
|
20
|
+
const moduleDir = normalizedModulePath.slice(0, normalizedModulePath.lastIndexOf("/"));
|
|
21
|
+
const require = createRequire(modulePath);
|
|
22
|
+
const isSeaRuntime = () => {
|
|
23
|
+
try {
|
|
24
|
+
const sea = require("node:sea");
|
|
25
|
+
return Boolean(sea.isSea?.());
|
|
26
|
+
}
|
|
27
|
+
catch {
|
|
28
|
+
return false;
|
|
21
29
|
}
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
|
|
30
|
+
};
|
|
31
|
+
// SEA: re-exec current binary with supervisor args.
|
|
32
|
+
// Non-SEA: execute Stagehand CLI entrypoint with supervisor args.
|
|
33
|
+
const resolveSupervisorCommand = (config) => {
|
|
34
|
+
const baseArgs = ["--supervisor", serializeConfigArg(config)];
|
|
35
|
+
if (isSeaRuntime()) {
|
|
36
|
+
return { command: process.execPath, args: baseArgs };
|
|
25
37
|
}
|
|
26
|
-
|
|
38
|
+
const cliPathCandidates = [`${moduleDir}/../cli.js`, `${moduleDir}/cli.js`];
|
|
39
|
+
const cliPath = cliPathCandidates.find((candidate) => fs.existsSync(candidate)) ?? null;
|
|
40
|
+
if (!cliPath)
|
|
41
|
+
return null;
|
|
42
|
+
const needsTsxLoader = fs.existsSync(`${moduleDir}/supervisor.ts`) &&
|
|
43
|
+
!fs.existsSync(`${moduleDir}/supervisor.js`);
|
|
44
|
+
return {
|
|
45
|
+
command: process.execPath,
|
|
46
|
+
args: needsTsxLoader
|
|
47
|
+
? ["--import", "tsx", cliPath, ...baseArgs]
|
|
48
|
+
: [cliPath, ...baseArgs],
|
|
49
|
+
};
|
|
27
50
|
};
|
|
51
|
+
// Single JSON arg keeps supervisor bootstrap parsing tiny and versionable.
|
|
52
|
+
const serializeConfigArg = (config) => `--supervisor-config=${JSON.stringify({
|
|
53
|
+
...config,
|
|
54
|
+
parentPid: process.pid,
|
|
55
|
+
})}`;
|
|
28
56
|
/**
|
|
29
57
|
* Start a supervisor process for crash cleanup. Returns a handle that can
|
|
30
58
|
* stop the supervisor during a normal shutdown.
|
|
31
59
|
*/
|
|
32
60
|
export function startShutdownSupervisor(config, opts) {
|
|
33
|
-
const resolved =
|
|
61
|
+
const resolved = resolveSupervisorCommand(config);
|
|
34
62
|
if (!resolved) {
|
|
35
|
-
opts?.onError?.(new ShutdownSupervisorResolveError(
|
|
63
|
+
opts?.onError?.(new ShutdownSupervisorResolveError("Shutdown supervisor entry missing (expected Stagehand CLI entrypoint)."), "resolve");
|
|
36
64
|
return null;
|
|
37
65
|
}
|
|
38
66
|
const child = spawn(resolved.command, resolved.args, {
|
|
39
|
-
|
|
67
|
+
// stdin is the parent lifeline.
|
|
68
|
+
// Preserve supervisor stderr so crash-cleanup debug lines are visible.
|
|
69
|
+
stdio: ["pipe", "ignore", "inherit"],
|
|
40
70
|
detached: true,
|
|
41
71
|
});
|
|
42
72
|
child.on("error", (error) => {
|
|
@@ -50,48 +80,15 @@ export function startShutdownSupervisor(config, opts) {
|
|
|
50
80
|
catch {
|
|
51
81
|
// best-effort: avoid keeping the event loop alive
|
|
52
82
|
}
|
|
53
|
-
try {
|
|
54
|
-
const message = { type: "config", config };
|
|
55
|
-
child.send?.(message);
|
|
56
|
-
}
|
|
57
|
-
catch {
|
|
58
|
-
// ignore IPC failures
|
|
59
|
-
}
|
|
60
|
-
const ready = new Promise((resolve) => {
|
|
61
|
-
let resolved = false;
|
|
62
|
-
const done = () => {
|
|
63
|
-
if (resolved)
|
|
64
|
-
return;
|
|
65
|
-
resolved = true;
|
|
66
|
-
clearTimeout(timer);
|
|
67
|
-
child.off("message", onMessage);
|
|
68
|
-
resolve();
|
|
69
|
-
};
|
|
70
|
-
const timer = setTimeout(done, READY_TIMEOUT_MS);
|
|
71
|
-
const onMessage = (msg) => {
|
|
72
|
-
const payload = msg;
|
|
73
|
-
if (payload?.type === "ready") {
|
|
74
|
-
done();
|
|
75
|
-
}
|
|
76
|
-
};
|
|
77
|
-
child.on("message", onMessage);
|
|
78
|
-
child.on("exit", done);
|
|
79
|
-
});
|
|
80
83
|
const stop = () => {
|
|
84
|
+
// Normal close path: terminate supervisor directly.
|
|
81
85
|
try {
|
|
82
|
-
|
|
83
|
-
child.send?.(message);
|
|
84
|
-
}
|
|
85
|
-
catch {
|
|
86
|
-
// ignore
|
|
87
|
-
}
|
|
88
|
-
try {
|
|
89
|
-
child.disconnect?.();
|
|
86
|
+
child.kill("SIGTERM");
|
|
90
87
|
}
|
|
91
88
|
catch {
|
|
92
89
|
// ignore
|
|
93
90
|
}
|
|
94
91
|
};
|
|
95
|
-
return { stop
|
|
92
|
+
return { stop };
|
|
96
93
|
}
|
|
97
94
|
//# sourceMappingURL=supervisorClient.js.map
|